本问题已经有最佳答案,请猛点这里访问。
如何枚举javascript对象的属性?
我实际上想列出所有定义的变量及其值,但我已经了解到定义一个变量实际上会创建一个窗口对象的属性。
足够简单:
1 2 3 4
| 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..in循环枚举对象的属性,但要小心。枚举将不仅返回要枚举的对象的属性,还返回任何父对象的原型的属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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():
1 2 3 4 5
| for (var name in myObject) {
if (myObject.hasOwnProperty(name)) {
alert(name);
}
} |
编辑:我不同意JasonBunting的说法,即我们不需要担心枚举继承的属性。枚举继承的属性是有危险的,因为它可以改变代码的行为。
不管这个问题是否存在于其他语言中,事实是它存在,而且javascript特别容易受到攻击,因为对对象原型的修改会影响子对象,即使修改是在实例化之后进行的。
这就是为什么javascript提供hasOwnProperty(),这也是为什么您应该使用它来确保第三方代码(或任何其他可能修改原型的代码)不会破坏您的代码。除了添加一些额外的字节代码外,使用hasOwnProperty()没有任何缺点。
已经多次提出的标准方法是:
1 2 3
| for (var name in myObject) {
alert(name);
} |
然而,InternetExplorer6、7和8在JavaScript解释器中有一个bug,它的作用是不枚举某些键。如果运行此代码:
1 2 3 4
| var obj = { toString: 12};
for (var name in obj) {
alert(name);
} |
如果会在除IE.IE之外的所有浏览器中警告"12",则会忽略此键。受影响的关键值包括:
- isPrototypeOf
- hasOwnProperty
- toLocaleString
- toString
- valueOf
为了安全起见,你必须使用如下工具:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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]);
}
} |
好消息是,ecmascript5定义了Object.keys(myObject)函数,它将对象的键返回为数组,并且一些浏览器(如safari 4)已经实现了该函数。
在现代浏览器(EcmaScript 5)中,要获取所有可枚举属性,可以执行以下操作:
对象键(obj)(检查链接以获取旧浏览器上向后兼容性的代码段)
或者获取不可枚举的属性:
对象.getownprotynames(obj)
检查ECMAScript 5兼容性表
其他信息:什么是可枚举属性?
我认为一个让我吃惊的例子是相关的:
1 2 3 4
| var myObject = { name:"Cody", status:"Surprised" };
for (var propertyName in myObject) {
document.writeln( propertyName +" :" + myObject[propertyName] );
} |
但令我惊讶的是,输出
1 2 3 4 5 6 7 8 9
| name : Cody
status : Surprised
forEach : function (obj, callback) {
for (prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop] !=="function") {
callback(prop);
}
}
} |
为什么?页面上的另一个脚本扩展了对象原型:
1 2 3 4 5 6 7
| Object.prototype.forEach = function (obj, callback) {
for ( prop in obj ) {
if ( obj.hasOwnProperty( prop ) && typeof obj[prop] !=="function" ) {
callback( prop );
}
}
}; |
1 2 3
| for (prop in obj) {
alert(prop + ' = ' + obj[prop]);
} |
简单的javascript代码:
1 2 3 4
| for(var propertyName in myObject) {
// propertyName is what you want.
// You can get the value like this: myObject[propertyName]
} |
jQuery:
1 2 3 4
| jQuery.each(obj, function(key, value) {
// key is what you want.
// The value is in: value
}); |
我找到了它…for (property in object) { // do stuff }将列出所有属性,因此窗口对象上的所有全局声明变量。
以下是枚举对象属性的方法:
1 2 3 4 5
| var params = { name: 'myname', age: 'myage' }
for (var key in params) {
alert(key +"=" + params[key]);
} |
如果使用的是underline.js库,则可以使用功能键:
1 2
| _.keys({one : 1, two : 2, three : 3});
=> ["one","two","three"] |
python的dict有"keys"方法,这非常有用。我认为在javascript中我们可以有这样的功能:
1 2 3 4 5 6 7 8 9
| 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,并且会导致您的项目出现不可预测的行为。@卡洛斯·鲁安娜的答案是获得物体钥匙的正确方法。
您可以使用循环的for。
如果要使用数组,请使用:
Object.keys(object1)
引用object.keys()。
如果您试图枚举属性以便针对对象编写新代码,我建议使用类似Firebug的调试器来直观地查看它们。
另一种方便的技术是使用原型的object.tojson()将对象序列化为json,它将同时显示属性名和值。
1 2 3
| var data = {name: 'Violet', occupation: 'character', age: 25, pets: ['frog', 'rabbit']};
Object.toJSON(data);
//-> '{"name":"Violet","occupation":"character","age": 25,"pets": ["frog","rabbit"]}' |
http://www.prototypejs.org/api/object/tojson
我仍然是javascript的初学者,但我编写了一个小函数来递归地打印对象及其子对象的所有属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| getDescription(object, tabs) {
var str ="{
";
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 +="
";
}
str += Array(tabs + 1).join("\t") +"}";
return str;
} |