【发布时间】:2010-09-10 07:16:07
【问题描述】:
如何枚举 JavaScript 对象的属性?
我实际上想列出所有定义的变量及其值,但我了解到定义变量实际上会创建窗口对象的属性。
【问题讨论】:
标签: javascript properties
如何枚举 JavaScript 对象的属性?
我实际上想列出所有定义的变量及其值,但我了解到定义变量实际上会创建窗口对象的属性。
【问题讨论】:
标签: javascript properties
足够简单:
for(var propertyName in myObject) {
// propertyName is what you want
// you can get the value like this: myObject[propertyName]
}
现在,您将无法通过这种方式获取私有变量,因为它们不可用。
编辑:@bitwiseplatypus 是正确的,除非您使用 hasOwnProperty() 方法,否则您将获得继承的属性 - 但是,我不知道为什么熟悉面向对象编程的人会期望更少!通常,提出这个问题的人已经受到道格拉斯·克罗克福德的警告,这仍然让我有点困惑。同样,继承是 OO 语言的正常部分,因此是 JavaScript 的一部分,尽管它是原型的。
现在,话虽如此,hasOwnProperty() 对过滤很有用,但我们不需要发出警告,就好像获取继承属性存在危险一样。
编辑 2:@bitwiseplatypus 提出了如果有人在您最初编写对象(通过其原型)之后的某个时间点向您的对象添加属性/方法时会发生的情况 - 虽然这是真的可能会导致意外行为,我个人并不认为这完全是我的问题。只是见仁见智。此外,如果我以这样一种方式设计事物,即在我的对象的构造过程中使用原型,但有代码迭代对象的属性并且我想要所有继承的属性,该怎么办?我不会使用hasOwnProperty()。然后,假设有人稍后添加了新属性。如果事情在那个时候表现不好,那是我的错吗?我不这么认为。我认为这就是为什么 jQuery 举例说明了扩展其工作方式的方法(通过jQuery.extend 和jQuery.fn.extend)。
【讨论】:
for(x in {}) 枚举任何东西感到惊讶,因为它看起来像一个简单的字典键迭代。这是非常出乎意料的,绝对值得特别警告。
for in 循环时的警告很好,因此您可以根据需要过滤继承的属性。将我的for loops 与hasOwnProperty 盲支票乱扔以迎合对JS 没有基本了解的人是不保证的。
for (thing in set) { ... },这很容易做到。
使用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() 没有任何缺点。
【讨论】:
Object.prototype.baz = 'quux';如何改变myObject对象?
已经多次提出的标准方式是:
for (var name in myObject) {
alert(name);
}
但是,Internet Explorer 6、7 和 8 在 JavaScript 解释器中存在一个错误,这会导致无法枚举某些键。如果你运行这段代码:
var obj = { toString: 12};
for (var name in obj) {
alert(name);
}
If 将在除 IE 之外的所有浏览器中显示“12”。 IE 将简单地忽略此键。受影响的键值是:
isPrototypeOfhasOwnPropertytoLocaleStringtoStringvalueOf为了在 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) (查看链接以获取 sn-p 以了解旧浏览器的向后兼容性)
或者获取不可枚举的属性:
Object.getOwnPropertyNames(obj)
【讨论】:
Object.getOwnPropertyNames(obj) 是您在处理某种错误对象(例如 TypeError)时想要的,因为这些属性是不可枚举的。
getOwnPropertyNames 似乎不适用于ErrorEvent 对象:它只列出isTrusted。但是for( var pn in errEv ) console.log( pn ); } 确实 工作。这是令人沮丧和不一致的。
我认为一个让我感到意外的案例是相关的:
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 原型:
Object.prototype.forEach = function (obj, callback) {
for ( prop in obj ) {
if ( obj.hasOwnProperty( prop ) && typeof obj[prop] !== "function" ) {
callback( prop );
}
}
};
【讨论】:
for (prop in obj) {
alert(prop + ' = ' + obj[prop]);
}
【讨论】:
简单的 JavaScript 代码:
for(var propertyName in myObject) {
// propertyName is what you want.
// You can get the value like this: myObject[propertyName]
}
jQuery:
jQuery.each(obj, function(key, value) {
// key is what you want.
// The value is in: value
});
【讨论】:
以下是枚举对象属性的方法:
var params = { name: 'myname', age: 'myage' }
for (var key in params) {
alert(key + "=" + params[key]);
}
【讨论】:
我找到了...for (property in object) { // do stuff } 将列出所有属性,因此窗口对象上的所有全局声明变量..
【讨论】:
如果你使用Underscore.js库,你可以使用函数keys:
_.keys({one : 1, two : 2, three : 3});
=> ["one", "two", "three"]
【讨论】:
【讨论】:
Python 的 dict 有 'keys' 方法,这真的很有用。我认为在 JavaScript 中我们可以有这样的东西:
function keys(){
var k = [];
for(var p in this) {
if(this.hasOwnProperty(p))
k.push(p);
}
return k;
}
Object.defineProperty(Object.prototype, "keys", { value : keys, enumerable:false });
编辑:但@carlos-ruana 的答案非常有效。我测试了Object.keys(window),结果符合我的预期。
5 年后编辑:扩展Object 不是一个好主意,因为它可能会与可能希望在其对象上使用keys 的其他库发生冲突,并且会导致您的项目出现不可预测的行为。 @carlos-ruana 答案是获取对象键的正确方法。
【讨论】:
如果您尝试枚举属性以便针对对象编写新代码,我建议您使用像 Firebug 这样的调试器来直观地查看它们。
另一个方便的技术是使用 Prototype 的 Object.toJSON() 将对象序列化为 JSON,这将显示属性名称和值。
var data = {name: 'Violet', occupation: 'character', age: 25, pets: ['frog', 'rabbit']};
Object.toJSON(data);
//-> '{"name": "Violet", "occupation": "character", "age": 25, "pets": ["frog","rabbit"]}'
【讨论】:
我仍然是 JavaScript 的初学者,但我写了一个小函数来递归打印对象及其子对象的所有属性:
getDescription(object, tabs) {
var str = "{\n";
for (var x in object) {
str += Array(tabs + 2).join("\t") + x + ": ";
if (typeof object[x] === 'object' && object[x]) {
str += this.getDescription(object[x], tabs + 1);
} else {
str += object[x];
}
str += "\n";
}
str += Array(tabs + 1).join("\t") + "}";
return str;
}
【讨论】: