简体   繁体   中英

JS function given to Array.prototype seen as array property

Array.prototype.testi = function() {console.log('hep');}
var b = new Array();

b.push(1, 5, 'b', 'c');

for (var i in b) {
    console.log(b[i]);
}

This will log (in chrome)

1
2
b
c
function () {console.log('hep');}

Or live example in http://jsfiddle.net/marqs/6VVka/1/

My question is, why is the function shown in the listing, even though it's given to the array prototype?

This has implications for extending browser functionalities that aren't used (for ex. IE extended Array.filter will behave differently if array in is used etc).

Edit: to clarify, I have no access to the code that does the for-in loop, as it's an external library. Thus the formulation of the question, more about "why is this so" than how to fix this.

The for-in loop will loop though all inherited properties of an object as well as its own properties. There is a way in Ecmascript 5 to hide your properties from enumeration, see Ecmascript 5 Objects and Properties , but this doesn't work in IE. The recommended way to iterate an array is to use the normal for loop:

for (var i = 0, len = b.length; i < len; i++)
    console.log(b[i])

This will have much better performance than the for-in loop as well because it avoids looking for properties on the object through the prototype chain. The len variable is used to cache the length of the array to avoid looking it up on each iteration of the loop. If you want to be slick, you can:

for (var i = b.length; i--;)
    console.log(b[i])

This iterates the array in reverse, and avoids the additional len variable.

JavaScript Objects are a collection of properties. Inside these properties, there are properties that describe the properties. The main one you are looking at here is the [[Enumerable]] property, which is a meta-property extended to most of the default objects in JavaScript, such as Array and Object. ECMAScript 5 defines a method for adding non-[[Enumerable]] objects, but that may not be widely supported in browsers.

One way to prevent enumerating over object properties you don't want is to check if the object property has an internal property method called [[GetOwnProperty]] . This ensures the property was directly invoked on the object and NOT inherited somewhere along the prototype chain.

var arr = ['a','b','c'], indexes = [];
Array.prototype.each = function() {/*blah*/}; 

for (var index in arr) {
    if (arr.hasOwnProperty(index)) {
    indexes.push(index);
    }
}

indexes; //["0", "1", "2"]

Source: http://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/

Any thing you add on an object's prototype, will appear in all of the instances of that object. This is how we can extend objects in javascript.

Please refer to: http://phrogz.net/js/classes/ExtendingJavaScriptObjectsAndClasses.html

Apparently Douglas Crockford has written about the same issue.

The flaw is that the for in statement, which can enumerate the keys stored in an object, produces all of the keys in the object's prototype chain, not just the keys in the object itself. This causes inherited methods to appear in the enumeration, which is bad. If would have been nicer if JavaScript did not contain this flaw, but fortunately we can program around it.

http://yuiblog.com/blog/2006/09/26/for-in-intrigue/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM