我如何枚举一个JavaScript对象的属性?
我实际上想列出所有已定义的变量及其值,但我已经了解到,定义变量实际上创建了窗口对象的属性。
我如何枚举一个JavaScript对象的属性?
我实际上想列出所有已定义的变量及其值,但我已经了解到,定义变量实际上创建了窗口对象的属性。
简单:
for(var propertyName in myObject) {
// propertyName is what you want
// you can get the value like this: myObject[propertyName]
}
现在,您不会以这种方式获得私有变量,因为它们不可用。
编辑:@bitwiseplatypus是正确的,除非你使用hasOwnProperty()方法,否则你将获得继承的属性-然而,我不知道为什么任何熟悉面向对象编程的人会期望更少!一般来说,提出这个问题的人都听过道格拉斯·克罗克福德的警告,这让我有点困惑。同样,继承是OO语言的一个正常部分,因此也是JavaScript的一部分,尽管它是原型。
现在,也就是说,hasOwnProperty()对于过滤是有用的,但我们不需要发出警告,就好像获取继承属性是危险的一样。
EDIT 2: @bitwiseplatypus brings up the situation that would occur should someone add properties/methods to your objects at a point in time later than when you originally wrote your objects (via its prototype) - while it is true that this might cause unexpected behavior, I personally don't see that as my problem entirely. Just a matter of opinion. Besides, what if I design things in such a way that I use prototypes during the construction of my objects and yet have code that iterates over the properties of the object and I want all inherited properties? I wouldn't use hasOwnProperty(). Then, let's say, someone adds new properties later. Is that my fault if things behave badly at that point? I don't think so. I think this is why jQuery, as an example, has specified ways of extending how it works (via jQuery.extend and 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()没有任何缺点。
如果您试图枚举属性以便针对对象编写新代码,我建议使用像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"]}'
http://www.prototypejs.org/api/object/tojson
我认为一个让我吃惊的案例是相关的:
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 (var name in myObject) {
alert(name);
}
然而,ie6、ie7和ie8在JavaScript解释器中有一个错误,导致一些键没有被枚举。如果你运行这段代码:
var obj = { toString: 12};
for (var name in obj) {
alert(name);
}
If将在除IE以外的所有浏览器中提醒“12”。IE会忽略这个键。受影响的键值为:
isPrototypeOf hasOwnProperty toLocaleString toString 返回对象的值
为了在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)已经实现了它。
简单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
});
如果你使用的是Underscore.js库,你可以使用函数键:
_.keys({one : 1, two : 2, three : 3});
=> ["one", "two", "three"]
下面是如何枚举一个对象的属性:
var params = { name: 'myname', age: 'myage' }
for (var key in params) {
alert(key + "=" + params[key]);
}
在现代浏览器(ECMAScript 5)中,要获得所有可枚举属性,您可以做:
种(obj) (请检查链接以获得在旧浏览器上向后兼容的代码片段)
或者也可以得到不可枚举的属性:
Object.getOwnPropertyNames (obj)
查看ECMAScript 5兼容性表
额外的信息: 什么是可枚举属性?
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(窗口),结果是我所期望的。
5年后再编辑:扩展Object不是一个好主意,因为它可能会与其他想要在其对象上使用键的库发生冲突,并且会在您的项目中导致不可预知的行为。@carlos-ruana答案是获取对象键的正确方法。
我仍然是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;
}