如何枚举 JavaScript 对象的属性?
我实际上想列出所有定义的变量及其值,但我了解到定义变量实际上会创建 window 对象的属性。
如何枚举 JavaScript 对象的属性?
我实际上想列出所有定义的变量及其值,但我了解到定义变量实际上会创建 window 对象的属性。
足够简单:
for(var propertyName in myObject) {
// propertyName is what you want
// you can get the value like this: myObject[propertyName]
}
现在,您不会以这种方式获得私有变量,因为它们不可用。
编辑:@bitwiseplatypus是正确的,除非您使用该hasOwnProperty()
方法,否则您将获得继承的属性 - 但是,我不知道为什么熟悉面向对象编程的人会期望更少!通常,提出此问题的人已受到道格拉斯·克罗克福德 (Douglas Crockford) 对此的警告,这仍然让我有些困惑。同样,继承是面向对象语言的正常部分,因此也是 JavaScript 的一部分,尽管它是原型。
现在,这么说,hasOwnProperty()
是用于过滤是有用的,但我们并不需要发出警告声,好像有什么东西在得到继承属性危险。
编辑 2:@bitwiseplatypus提出了如果有人在您最初编写对象(通过其原型)之后的某个时间点向您的对象添加属性/方法时会发生的情况 - 虽然这确实可能导致意外行为,我个人并不认为这完全是我的问题。只是见仁见智。此外,如果我以这样一种方式设计事物,即在构建对象期间使用原型,但具有迭代对象属性的代码并且我想要所有继承的属性,该怎么办?我不会使用hasOwnProperty()
. 然后,假设有人稍后添加新属性。如果当时事情表现不佳,那是我的错吗?我不这么认为。我认为这就是为什么 jQuery 作为一个例子,指定了扩展它的工作方式的方法(通过jQuery.extend
和jQuery.fn.extend
)。
使用for..in
循环枚举对象的属性,但要小心。枚举不仅会返回被枚举对象的属性,还会返回任何父对象的原型。
var myObject = {foo: 'bar'};
for (var name in myObject) {
alert(name);
}
// results in a single alert of 'foo'
Object.prototype.baz = 'quux';
for (var name in myObject) {
alert(name);
}
// results in two alerts, one for 'foo' and one for 'baz'
为避免在枚举中包含继承的属性,请检查hasOwnProperty()
:
for (var name in myObject) {
if (myObject.hasOwnProperty(name)) {
alert(name);
}
}
编辑:我不同意 JasonBunting 的声明,即我们不需要担心枚举继承的属性。还有就是在枚举,你是不是希望在继承属性,因为它可以改变你的代码的行为危险。
这个问题在其他语言中是否存在并不重要;事实是它存在,而且 JavaScript 尤其容易受到攻击,因为对对象原型的修改会影响子对象,即使修改发生在实例化之后。
这就是 JavaScript 提供 的原因hasOwnProperty()
,也是您应该使用它以确保第三方代码(或任何其他可能修改原型的代码)不会破坏您的代码的原因。除了添加一些额外的代码字节外,使用hasOwnProperty()
.
已经被多次提出的标准方式是:
for (var name in myObject) {
alert(name);
}
但是,Internet Explorer 6、7 和 8 在 JavaScript 解释器中存在一个错误,这会导致某些键没有被枚举。如果您运行此代码:
var obj = { toString: 12};
for (var name in obj) {
alert(name);
}
如果将在除 IE 之外的所有浏览器中警告“12”。IE 将简单地忽略此键。受影响的键值为:
isPrototypeOf
hasOwnProperty
toLocaleString
toString
valueOf
要在 IE 中真正安全,您必须使用以下内容:
for (var key in myObject) {
alert(key);
}
var shadowedKeys = [
"isPrototypeOf",
"hasOwnProperty",
"toLocaleString",
"toString",
"valueOf"
];
for (var i=0, a=shadowedKeys, l=a.length; i<l; i++) {
if map.hasOwnProperty(a[i])) {
alert(a[i]);
}
}
好消息是 EcmaScript 5 定义了这个Object.keys(myObject)
函数,它将对象的键作为数组返回,并且一些浏览器(例如 Safari 4)已经实现了它。
在现代浏览器 (ECMAScript 5) 中,要获取所有可枚举的属性,您可以执行以下操作:
Object.keys(obj) (检查链接以获取在旧浏览器上向后兼容的片段)
或者获取不可枚举的属性:
Object.getOwnPropertyNames(obj)
附加信息: 什么是可枚举属性?
我认为一个让我感到意外的案例是相关的:
var myObject = { name: "Cody", status: "Surprised" };
for (var propertyName in myObject) {
document.writeln( propertyName + " : " + myObject[propertyName] );
}
但令我惊讶的是,输出是
name : Cody
status : Surprised
forEach : function (obj, callback) {
for (prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop] !== "function") {
callback(prop);
}
}
}
为什么?页面上的另一个脚本扩展了对象原型:
Object.prototype.forEach = function (obj, callback) {
for ( prop in obj ) {
if ( obj.hasOwnProperty( prop ) && typeof obj[prop] !== "function" ) {
callback( prop );
}
}
};