Как очистить массив, как кросс-браузер (IE8)?
У меня есть объект, который похож на массив. Это означает, что он имеет числовые свойства (0
, 1
, 2
...) и length
имущество.
В его прототипе я объявляю метод для его очистки, например:
'clear': function() {
Array.prototype.splice.call(this, 0, this.length);
return this;
}
Это работает, как и ожидалось, в большинстве браузеров, но не в Internet Explorer.
Возьмите совершенно правильный объект, похожий на массив:
var arrayLike = {
length: 3,
'0': 'a',
'1': 'b',
'2': 'c'
};
И склеить это ясно:
Array.prototype.splice.call(arrayLike, 0, arrayLike.length);
В браузере, соответствующем стандартам, это правильный результат:
arrayLike.length == 0 ;
arrayLike[0] == undefined;
arrayLike[1] == undefined;
arrayLike[2] == undefined;
Но в IE 8 это то, что вы получаете:
arrayLike.length == 0 ; // (!!)
arrayLike[0] == 'a';
arrayLike[1] == 'b';
arrayLike[2] == 'c';
Да, он даже не работает или не работает, он работает столько, сколько хочет.
Теперь я думаю Array.prototype.splice.call
это единственный способ изначально очистить массивоподобный объект. Возможно, я мог бы заполнить его в закрытой копии условно для IE8 (возможно, одноразовый удар по производительности для других браузеров, но только один раз).
Или, может быть, есть другой способ очистки объекта? Это тоже родное в IE8? Есть что-то, чего я не вижу?
Ps: JsFiddle для вас, чтобы работать в IE8.
3 ответа
IE запутался... Кажется, даже если вы расширяете объект массива, IE запутывает соединение. Смотрите мое тестирование ниже:
// create an object constructor
var arrayLike = function() {
this.clear = function() {
this.splice( 0, this.length );
};
};
// use prototypical inheritance to inherit array functionality
arrayLike.prototype = [];
arrayLike.constructor = arrayLike;
// testing clear method fails...
var arrayLikeObject = new arrayLike();
arrayLikeObject.push( 'foo' );
console.log( arrayLikeObject[ 0 ] ); // outputs foo
arrayLikeObject.clear();
console.log( arrayLikeObject[ 0 ] ); // outputs foo
// yet the same method works on a normal array
var test = [];
test.push( 'foo2' );
test.splice( 0, test.length );
console.log( test[0] ); // outputs undefined
какого черта IE...
Я чувствую, что вы не должны использовать Array.prototype.splice.call
на объекте, который не является Array
, Мне это кажется хакерским.
Да, это, вероятно, работает в большинстве браузеров, но вы пытаетесь выполнить операцию, предназначенную для одного прототипа, над объектом, который не принадлежит этому прототипу. Я не фанат IE, но это выглядит для меня как хакерство, так что вы не можете заплакать, когда это не сработает.
Мой 2¢ либо создать новый " Array
как объект Array
в качестве прототипа, пример:
var ArrayLike = function(){
this.push.apply(this, arguments);
};
ArrayLike.prototype = Array.prototype;
ArrayLike.constructor = function(){};
ArrayLike.prototype.clear = function(){
// Array.prototype.splice.call(this, 0, this.length);
this.splice(0, this.length); // all of Array's methods are available to ArrayLike
return this;
}
var arrayLike = new ArrayLike('a', 'b', 'c');
console.log(arrayLike.length); // 3
arrayLike.clear(); // clear
console.log(arrayLike.length); // 0
... или напишите свой собственный метод.
Чувак, это смешно. Array.prototype.splice
очень странно ломается в IE8.
Я должен показать вам это (пропустите, если хотите, решение ниже).
Как вы уже видели, это предупредит "а" в IE, верно?
// Create an array-like object.
var arrayLike = {
length: 1,
'0': 'a'
};
// Clean it with splice. This should work in ES5.
Array.prototype.splice.call(arrayLike, 0, 2);
// Note that IE does set the length to zero. We need to check an item.
alert(arrayLike[0]);
А что если мы установим недопустимую длину? Специально для этого эффекта "3" ("2" даст те же результаты в IE8).
Теперь, что это предупреждение в IE8?
var arrayLike = {
length: 3, // <--
'0': 'a'
};
Array.prototype.splice.call(arrayLike, 0, 2);
alert(arrayLike[0]);
В любом случае, я не собираюсь полагаться на этот странный способ работы, я не хочу иметь ужасно странную ошибку в производстве. Вот как это исправить:
Во-первых, у вас есть ваш код, завернутый в право IIFE? Вам следует. Во-вторых, проверьте, что у вас есть личная копия Array.prototype.splice
, Я объявляю эти вещи в начале моего IIFE.
// Call it whatever you want.
var protoSplice = Array.prototype.splice;
Затем в каком-либо методе инициализации (или в любое удобное для вас время, убедитесь, что он есть до его использования), вызовите метод polyfill.
polyfill();
Который вызывает тесты и исправления.
function polyfill() {
// ...
genericSpliceWorks() || fixGenericSplice();
// ...
}
Вот методы, которые он использует:
function genericSpliceWorks() {
// Create an array-like object.
var arrayLike = {
length: 1,
'0': true
};
// Clean it with splice. This should work in ES5.
protoSplice.call(arrayLike, 0, 2);
// Note that IE does set the length to 0. We need to check an item.
return !arrayLike[0];
}
function fixGenericSplice() {
// Re-set our local protoSplice variable to something that works.
// Note: this implementation only works with the first two arguments
// of splice. This means that it does not add extra elements to the
// array. It's as much as I need.
protoSplice = function(index, count) {
// If count is more than zero, run until it's zero, decrementing
// each time.
while (count--) {
// Remove an array item from index, while incrementing index
// for the next time.
delete this[index++];
// Decrement the length.
this.length--;
}
};
}
Та-да! Теперь работает:)