可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I was attempting to extend Javascript's Object type with a function that retrieves all of the property names that are part of that object (basically what PHP's array_keys()
function does to associative arrays).
Object.prototype.keys = function() { var a = []; for (var property in this) { a.push(property); } return a; }; var a = {a:1,b:2,c:3,d:4}; alert(a.toSource()); var b = a.keys(); alert(b.toSource());
When the variable b
was alerted, I was expecting to see ["a","b","c","d"]
, instead I'm seeing ["a","b","c","d","keys"]
.
It appears the for-in loop is including the prototyped keys()
functions.
Is it possible to avoid this behaviour whilst still prototying, or should I just avoid prototyping all together?
回答1:
Ahh the joys of extending the built-ins. for..in
checks up the entire prototype chain of the object being iterated.
What you need (and I believe this is de-facto now) is a check with hasOwnProperty
in your loop:
for (var property in this) { if (this.hasOwnProperty(property)) { a.push(property); } }
hasOwnProperty
ensures that you only get properties that are directly defined on your object (i.e. not up the prototype chain).
回答2:
For most situations, you should avoid extending the native Object.prototype
. When you extend it, ALL objects receive those new properties.
Looping over an object properties is a really common task, and as you noted, you were experiencing an unexpected behavior.
I have not seen many people who always use the hasOwnProperty
function in their code, I would say that under "controlled environments", maybe being a solo developer working on a project, you could manage those issues, but when the things get bigger, and you have more developers involved, this can cause a lot of problems.
What about making a static function on Object?
Object.keys = function(obj) { var a = []; for (var property in obj) { if (obj.hasOwnProperty(property)) { a.push(property); } } return a; }; var a = {a:1,b:2,c:3,d:4}; alert(a.toSource()); var b = Object.keys(a); alert(b.toSource());
回答3:
This also works:
var items = [ { id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }, { id: 3, name: 'Item 3' } ]; items.forEach(function(item, index) { console.log(item); });