如何清空类似数组的对象,跨浏览器(IE8)?

时间:2012-10-01 21:00:39

标签: javascript internet-explorer-8 cross-browser javascript-objects array-splice

我有一个类似于数组的对象。这意味着它具有数字属性(012 ...)和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 个答案:

答案 0 :(得分:1)

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 ...

答案 1 :(得分:0)

我的直觉是你不应该在不是Array.prototype.splice.call的对象上使用Array。对我来说,这似乎是黑客。

是的,它可能适用于大多数浏览器,但是您尝试在不属于该原型的对象上执行为一个原型设计的操作。我不喜欢IE浏览器,但这对我来说就像hackery一样,所以当它无法解决时你就不会哭。

我的2¢是使用Array作为原型创建新的“Array - like”对象,例如:

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

...或者编写自己的方法。

答案 2 :(得分:0)

伙计,这很有趣。在IE8中,Array.prototype.splice 非常奇怪的方式 被打破。

我必须告诉你(如果你愿意,请跳过它,下面的解决方案)。

如您所见,这会在IE中警告“a”,对吗?

// 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]);

jsfiddle

现在,如果我们将其设置为无效长度怎么办?特别是对于这种效果,“3”(“2”将在IE8中产生相同的结果)。

现在,在IE8中这个警报是什么?

var arrayLike = {
    length: 3,      // <--
    '0': 'a'
};

Array.prototype.splice.call(arrayLike, 0, 2);

alert(arrayLike[0]);

jsfiddle

无论如何,我不会依赖那种奇怪的工作方式,我不想在制作中有一个非常奇怪的错误。 您可以通过以下方式解决问题:

首先,您的代码是否包含在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--;

        }

    };

}

钽哒!它现在有效:)