IE8 for…in enumerator

2019-02-02 00:21发布

问题:

So I am using this in IE8:

var hi=["hi", "lo", "foo", "bar"];
for(i in hi){console.log(i)};
//WTF is that indexOf i value?
LOG: 0
LOG: 1
LOG: 2
LOG: 3
LOG: indexOf
undefined

In chrome and others, I'll just get 0-3, no mysterious "indexOf" thing. Why and what's the fix?

回答1:

Don't use for...in for arrays. It's best to use the traditional for loop in that case.

The reason is because for...in looks at the array as an object, and therefore properties like indexOf or length may be included in the loop. The normal for loop only deals with numeric keys, so this problem is avoided.

On a side note, unwanted properties could show up when iterating over plain objects as well (as others have noted, properties you add to the object's prototype will show up). You can get around this by writing your for...in loops this way:

var obj = { ... };
for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    var item = obj[prop];
    ...
  }
}

To be clear though: you still shouldn't use this method on arrays.



回答2:

You're using the wrong type of loop for an array - for ... in ... will also include any enumerable properties of the object, which in your case includes the .indexOf() method.

Use this instead:

var i, n = hi.length;
for (i = 0; i < n; ++i) {
    console.log(i, hi[i]);
}

Chrome and other up to date browsers implement ECMAScript 5, and correctly mark all built-in methods as non-enumerable properties.



回答3:

This is happening because a script you are including on your page is adding the indexOf method to Array.prototype. This means all arrays inherit an indexOf method, which is good, since it means you can use that method even in IE8.

But, since there is no way to mark a property as non-enumerable in IE8, you will end up seeing it every time you enumerate over all the properties of the array, which is what you do in a for-in loop. You probably wanted a for loop instead.