如何枚举JavaScript对象的属性?

How do I enumerate the properties of a JavaScript object?

本问题已经有最佳答案,请猛点这里访问。

如何枚举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.extendjQuery.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;
}