0

今天出现了一个奇怪的bug。在我们的应用程序中,在一个文件中,所有对象都附加了一个函数,就好像它们是原型一样。我们没有对我们的数组进行原型设计,但我已经处理了数组和对象具有原型的其他东西,当您执行 for(this in that) 循环时,原型将作为项目包含在内,我们必须过滤它们。所以,两部分问题:

  1. 如果您对数组进行原型制作,索引会增加 + # 个原型吗?所以如果 array(a,b,c) 有 array.prototype.function(),它的索引计数是 3 还是 4?

  2. 这应该发生吗?

我们认为我们拥有的其中一个 jquery 插件是邪恶的。

4

3 回答 3

2

通过“索引计数”,我假设您的意思是length财产。在这种情况下,您的第一个问题的答案是“否”。该length属性与数组的最高数字索引相关联。因此,例如,如果您有以下代码,arr.length则将是4

var arr = [];
arr[3] = true;
arr.length; //is 4

但是,您提到了 for-in 循环,它在这种情况下具有奇怪的行为。如果我们(从上面)执行 for-in arr,我们会得到以下结果:

var output = "";
for (i in arr) { //Don't do this!
    output += i;
} 
output; //is "3" (not "0123" as you might expect)

正如我所提到的,原型属性对长度没有影响:

Array.prototype.foo = true;
var arr = [];
arr[3] = true;
arr.length; //is 4

但是,它们确实会影响 for-in 循环(在正常情况下):

var output = "";
for (i in arr) { //arr from the previous code block.
    output += i;
} 
output; //is "3foo" (or maybe "foo3", there's no guarantee form the spec either way)

有几种方法可以解决这个问题。首先,由于这种胡说八道,你真的不应该在数组对象上使用 for-in。但是,如果出于某种原因必须这样做,则应始终使用hasOwnProperty()过滤器保护 for-in 循环,如下所示:

var output = "";
for (i in arr) { //arr from the previous code block
    if (arr.hasOwnProperty(i)) {
        output += i;
    }
} 
output; //is "3"

同样,不能保证在 for-in 上订购。因此,如果arr[1,1,1],您可能会得到outputas "201"(尽管不太可能)。

另一种选择是尝试通过使用 ES5 的功能(如果存在)来保护自己免受其他人的错误编码,通过将它们设置为不可枚举来保护对象级别的原型属性。你会这样做:

var foo = (function() { /* do something */ });
if(typeof Object.defineProperty === "function") { //If ES5
    Object.defineProperty(Array.prototype, "foo", {
        value: foo,
        enumerable: false //make it not enumerable
    });
} else { //For older browsers
    Array.prototype.foo = foo;
}

var arr = [], output = "";
arr[3] = true;

for(i in arr) { //Seriously, don't do this.
    output += i;
}
output; //is "3"

我不能过分强调对数组进行 for-in 是一个坏主意。事实上,在几乎所有情况下,我都倾向于避免使用 for-in,因为你永远不知道外面是否有人想成为一个混蛋,并将其扔到他们的代码中间:

Object.prototype.ponies = "Ponies!";
于 2012-09-06T17:47:59.287 回答
2

尽管数组是对象,因此可以具有许多属性,但只有整数属性才算入array自身。

var a = [];
alert(a.length); // 0
a.foo = "Ha";
alert(a.length); // 0
a[1] = 10;
alert(a.length); // 1

Array.prototype.shuffle = function() { ... }
alert(a.length); // 1

尽管不建议使用它for ... in来处理数组,但有些人仍然这样做。 for ... in会发现fooshuffle

于 2012-09-06T17:28:08.570 回答
1

如果您避免使用for (var i in array)来迭代您的数组并仅通过从 0 到 的数字索引对其进行迭代array.length - 1,那么如果有人向数组原型添加某些内容,您将不会遇到问题。这正是您应该避免使用for/in迭代数组的技术的原因。

无论向数组或数组原型中添加了多少属性或方法,都有一些迭代数组的安全方法:

for (var i = 0, len = array.length; i < len; i++) {
    // access array[i] here
}

var i = 0, len = array.length;
while (i < len) {
    // access array[i] here
    i++;
}
于 2012-09-06T17:32:34.283 回答