如何枚举JavaScript对象的属性?

如何枚举JavaScript对象的属性?

我实际上想列出所有定义的变量及其值,但我了解到定义变量实际上会创建windows对象的属性。

615087 次浏览

足够简单:

for(var propertyName in myObject) {
// propertyName is what you want
// you can get the value like this: myObject[propertyName]
}

现在,您不会以这种方式获得私有变量,因为它们不可用。


编辑:@张学良是正确的,除非你使用hasOwnProperty()方法,否则你将获得继承的属性——然而,我不知道为什么熟悉面向对象编程的人会期望更少!通常,提出这个问题的人已经受到Douglas Crockford关于这个的警告,这仍然让我有点困惑。再次,继承是OO语言的正常部分,因此也是JavaScript的一部分,尽管它是原型。

现在,也就是说,hasOwnProperty()对过滤很有用,但我们不需要发出警告,就好像获取继承的属性有危险一样。

编辑2:@张学良提出了这样一种情况,即如果有人在你最初编写对象(通过其原型)的时间之后的某个时间点向你的对象添加属性/方法,尽管这确实可能会导致意想不到的行为,但我个人并不完全认为这是我的问题。只是一个意见问题。此外,如果我设计事物的方式是,我在构建对象的过程中使用原型,但代码迭代了对象的属性,我想要所有继承的属性,怎么办?我不会使用hasOwnProperty()。然后,假设有人后来添加了新属性。如果当时事情表现不好,是我的错吗?我不这么认为。我认为这就是为什么jQuery作为一个例子,指定了扩展它工作方式的方法(通过jQuery.extendjQuery.fn.extend)。

我找到了…for (property in object) { // do stuff }将列出所有属性,因此列出窗口对象上的所有全局声明变量。

使用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等调试器直观地查看它们。

另一种方便的技术是使用原型的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

for (prop in obj) {
alert(prop + ' = ' + obj[prop]);
}

我认为一个让我大吃一惊的案例是相关的:

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 );
}
}
};

已经多次提出的标准方法是:

for (var name in myObject) {
alert(name);
}

然而,Internet Explorer 6、7和8在JavaScript解释器中有一个bug,这会导致某些键未枚举。如果您运行此代码:

var obj = { toString: 12};
for (var name in obj) {
alert(name);
}

if将在除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)函数,它将对象的键作为数组返回,并且一些浏览器(例如Safari4)已经实现了它。

简单的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)中,要获取所有可枚举属性,您可以执行以下操作:

Object.keys(obj) (检查链接以获取在旧浏览器上向后兼容的片段)

或者也可以获取不可枚举的属性:

Object.getOwnProperties tyNames(obj)

检查ECMAScript 5兼容性表

其他信息: 什么是可枚举属性?

Python的字典有“key”方法,这真的很有用。我认为在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不是一个好主意,因为它可能会与其他可能希望在其对象上使用keys的库发生冲突,这将导致您的项目出现不可预测的行为。

您可以使用for of循环。

如果你想要一个数组,使用:

Object.keys(object1)

参考。Object.keys()

我仍然是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;
}