如何枚举 JavaScript 对象的属性?

IT技术 javascript properties
2021-01-13 00:41:47

如何枚举 JavaScript 对象的属性?

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

6个回答

足够简单:

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

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


编辑:@bitwiseplatypus是正确的,除非您使用该hasOwnProperty()方法,否则您将获得继承的属性 - 但是,我不知道为什么熟悉面向对象编程的人会期望更少!通常,提出此问题的人已受到道格拉斯·克罗克福德 (Douglas Crockford) 对此的警告,这仍然让我有些困惑。同样,继承是面向对象语言的正常部分,因此也是 JavaScript 的一部分,尽管它是原型。

现在,这么说,hasOwnProperty() 用于过滤是有用的,但我们并不需要发出警告声,好像有什么东西在得到继承属性危险。

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

我想大多数人都对for(x in {})枚举任何东西感到惊讶,因为它看起来像一个简单的字典键迭代。这是非常出乎意料的,绝对值得特别警告。
2021-03-10 00:41:47
有趣的是,这对用 Object.defineProperty 定义的 getter 属性不起作用,但对直接 getter 有效。请参阅我的jsfiddle
2021-03-12 00:41:47
@DavidSpector 猜测此消息指的是迭代器不是为对象属性实现的而是为数组元素实现的。你可能省略了 let/var 并写了for (thing in set) { ... }这很容易做到。
2021-03-12 00:41:47
我认为@bitwiseplatypus 只是在说“小心”。在我看来,JavaScript 的 for/in 应该只在提到 hasOwnProperty() 和其他不太明显的原型继承边缘情况的同时进行教授。
2021-03-17 00:41:47
我想知道人们实际上遇到过多少次这样的错误。我做过一次,而且很容易发现。教授 JSfor in循环时的警告很好,因此您可以根据需要过滤继承的属性。为了迎合对 JS没有基本了解的人,for loop用盲目的hasOwnProperty检查乱扔我的s没有必要的。
2021-04-03 00:41:47

使用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().

hasOwnProperty 的拥护者通常是那些具有以下特点的人:a) 遭受过激进的公共库 [例如:Prototype.js 大约 2003 年],或 b) 为异构系统建立了基础(想想:门户网站)。其他所有人都应该将 hasOwnProperty 包装在迭代器模式中,然后出去喝啤酒。
2021-03-20 00:41:47
对于我作为 js 新手的理解,如何Object.prototype.baz = 'quux';更改myObject对象?
2021-03-29 00:41:47
需要并使用此模式是因为 javascript 将“Actor 对象”与“哈希表”混为一谈。当对象是对行为和特征描述时,通常的规则适用,你想知道对象的属性,而不用关心它们是如何到达那里的。另一方面,如果您使用对象作为键值存储,那么您很可能只对实际存储在对象上的实际键感兴趣。其他属性纯属巧合,不代表对象的实际状态。其他语言通过不同的类型解决了这种区别。
2021-04-09 00:41:47

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

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

但是,Internet Explorer 6、7 和 8 在 JavaScript 解释器中存在一个错误,这会导致某些键没有被枚举。如果您运行此代码:

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

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

在现代浏览器 (ECMAScript 5) 中,要获取所有可枚举的属性,您可以执行以下操作:

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

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

Object.getOwnPropertyNames(obj)

检查 ECMAScript 5 兼容性表

附加信息: 什么是可枚举属性?

Object.getOwnPropertyNames(obj) 如果您正在处理某种 Error 对象(例如 TypeError),这是您想要的,因为这些属性是不可枚举的。
2021-03-12 00:41:47
@vossad01 不幸的是,getOwnPropertyNames它似乎不适用于ErrorEvent对象:它只列出isTrusted. 但是for( var pn in errEv ) console.log( pn ); } 确实有效。这是令人沮丧和不一致的。
2021-03-16 00:41:47

我认为一个让我感到意外的案例是相关的:

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 );
    }
  }
};
@cyberhobo - 理解,但是谁导致它崩溃?你?不,有人追过来了,没有考虑清楚,也不知道自己陷入了什么境地,因此他们是白痴。任何称职的 JavaScript 人都知道,修改最初不是他们的任何对象的原型可能是在玩火。
2021-03-14 00:41:47
鉴于 JavaScript 开发的现代趋势,修改任何基本类型的原型对我来说似乎是一个错误的决定;还有其他方法可以为大多数猫剥皮,这首先促使人们这样做。
2021-03-15 00:41:47
是的,我的观点是另一个脚本可以向对象原型添加任何内容。这些变化可能存在,也可能不存在,并且添加的方法可能会做任何事情。我不认为 forEach 的这个例子是好的 - 只是脚本可能会修改其他脚本的 for .. in 结果。
2021-03-16 00:41:47
我同意,但如果其他代码做到了,我仍然不希望我的代码崩溃。
2021-03-24 00:41:47
有趣的是,我想这意味着在重新定义 forEach 函数时可能不调用回调,这可能会使枚举属性中断。
2021-04-02 00:41:47