0

我有一个类似数组的对象。这意味着它具有数字属性 ( 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 中运行。

4

3 回答 3

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是什么鬼...

于 2012-10-01T23:54:44.510 回答
0

我的直觉是你不应该Array.prototype.splice.call在一个不是Array. 对我来说,这似乎很骇人听闻。

是的,它可能适用于大多数浏览器,但您正试图在不属于该原型的对象上执行为一个原型设计的操作。我不是 IE 的粉丝,但这在我看来就像骇客,所以当它不起作用时你不能大喊大叫。

我的 2¢ 是Array使用原型创建新的“-like”对象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

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

于 2012-10-01T21:23:14.263 回答
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--;

        }

    };

}

达达!它现在可以工作了:)

于 2012-10-02T20:07:10.667 回答