遍历对象属性

var obj = {name: "Simon",age: "20",clothing: {style: "simple",hipster: false}}
for(var propt in obj){console.log(propt + ': ' + obj[propt]);}

变量propt如何表示对象的属性?它不是内置方法或属性。为什么它会出现在对象中的每个属性中?

1550216 次浏览

这是for...in statementMDNECMAScript规范)。

您可以将其读为“for每个属性obj对象,依次将每个属性分配给PROPT变量”。

这只是一个for...in循环。看看在Mozilla留档

您的for循环正在迭代对象obj的所有属性。propt在for循环的第一行中定义。它是一个字符串,是obj对象属性的名称。在循环的第一次迭代中,propt将是“名称”。

JavaScript中的对象是属性的集合,因此可以在for each语句中循环。

您应该将obj视为键值集合。

迭代属性需要这个额外的hasOwnProperty检查:

for (var prop in obj) {if (Object.prototype.hasOwnProperty.call(obj, prop)) {// do stuff}}

这是必要的,因为对象的原型包含对象的附加属性,这些属性在技术上是对象的一部分。这些附加属性是从基对象类继承的,但仍然是obj的属性。

#0只是检查这是否是特定于该类的属性,而不是从基类继承的属性。


也可以通过对象本身调用hasOwnProperty

if (obj.hasOwnProperty(prop)) {// do stuff}

但是如果对象有一个同名的不相关字段,这将失败:

var obj = { foo: 42, hasOwnProperty: 'lol' };obj.hasOwnProperty('foo');  // TypeError: hasOwnProperty is not a function

这就是为什么通过Object.prototype调用它更安全:

var obj = { foo: 42, hasOwnProperty: 'lol' };Object.prototype.hasOwnProperty.call(obj, 'foo');  // true

从JavaScript 1.8.5开始,您可以使用Object.keys(obj)来获取对象本身定义的属性数组(obj.hasOwnProperty(key)返回true的属性)。

Object.keys(obj).forEach(function(key,index) {// key: the name of the object key// index: the ordinal position of the key within the object});

这比使用for-in循环更好(也更具可读性)。

它在这些浏览器上支持:

  • Firefox(Gecko):4(2.0)
  • Chrome: 5
  • Internet Explorer:9

请参阅Mozilla Developer NetworkObject.keys()的参考以获取更多信息。

for… in循环所做的是它创建一个新变量(var一些变量),然后将给定对象的每个属性一个接一个地存储在这个新变量(一些变量)中。因此,如果你使用block{},你可以迭代。考虑下面的例子。

var obj = {name:'raman',hobby:'coding',planet:'earth'};
for(var someVariable in obj) {//do nothing..}
console.log(someVariable); // outputs planet

for… in循环代表对象中的每个属性,因为它就像for循环。您在for… in循环中通过执行以下操作定义了提示:

    for(var propt in obj){alert(propt + ': ' + obj[propt]);}

for… in循环遍历对象的可枚举属性。无论您定义哪个变量,或放入for… in循环中,每次它迭代到下一个属性时都会发生变化。for… in循环中的变量遍历键,但它的值是键的值。例如:

    for(var propt in obj) {console.log(propt);//logs nameconsole.log(obj[propt]);//logs "Simon"}

您可以看到变量与变量的值有何不同。相比之下,for… of循环则相反。

我希望这能有所帮助。

我想对上面的答案进行补充,因为你可能与Javascript有不同的意图。JSON对象和Javascript对象是不同的东西,你可能想使用上面提出的解决方案迭代JSON对象的属性,然后感到惊讶。

假设你有一个JSON对象,如下所示:

var example = {"prop1": "value1","prop2": [ "value2_0", "value2_1"],"prop3": {"prop3_1": "value3_1"}}

遍历其“属性”的错误方式:

function recursivelyIterateProperties(jsonObject) {for (var prop in Object.keys(example)) {console.log(prop);recursivelyIterateProperties(jsonObject[prop]);}}

当遍历prop1prop2prop3_1的属性时,您可能会惊讶地看到控制台记录01等。这些对象是序列,序列的索引是Javascript中该对象的属性。

递归迭代JSON对象属性的更好方法将首先检查该对象是否为序列:

function recursivelyIterateProperties(jsonObject) {for (var prop in Object.keys(example)) {console.log(prop);if (!(typeof(jsonObject[prop]) === 'string')&& !(jsonObject[prop] instanceof Array)) {recursivelyIterateProperties(jsonObject[prop]);
}            
}}

还添加了递归方式:

function iterate(obj) {// watch for objects we've already iterated so we won't end in endless cycle// for cases like var foo = {}; foo.bar = foo; iterate(foo);var walked = [];var stack = [{obj: obj, stack: ''}];while(stack.length > 0){var item = stack.pop();var obj = item.obj;for (var property in obj) {if (obj.hasOwnProperty(property)) {if (typeof obj[property] == "object") {// check if we haven't iterated through the reference yetvar alreadyFound = false;for(var i = 0; i < walked.length; i++){if (walked[i] === obj[property]){alreadyFound = true;break;}}// new object referenceif (!alreadyFound){walked.push(obj[property]);stack.push({obj: obj[property], stack: item.stack + '.' + property});}}else{console.log(item.stack + '.' + property + "=" + obj[property]);}}}}}

用法:

iterate({ foo: "foo", bar: { foo: "foo"} });

在这里,我迭代每个节点并创建有意义的节点名称。如果你注意到,instance Of Array和instance Of Object几乎做同样的事情(在我的应用程序中,我给出了不同的逻辑)

function iterate(obj,parent_node) {parent_node = parent_node || '';for (var property in obj) {if (obj.hasOwnProperty(property)) {var node = parent_node + "/" + property;if(obj[property] instanceof Array) {//console.log('array: ' + node + ":" + obj[property]);iterate(obj[property],node)} else if(obj[property] instanceof Object){//console.log('Object: ' + node + ":" + obj[property]);iterate(obj[property],node)}else {console.log(node + ":" + obj[property]);}}}}

注意-我受到Ondrej Svejdar答案的启发。但是这个解决方案具有更好的性能和更少的模棱两可

jQuery现在允许您这样做:

$.each( obj, function( key, value ) {alert( key + ": " + value );});

您基本上希望循环遍历对象中的每个属性。

jsfiddle

var Dictionary = {If: {you: {can: '',make: ''},sense: ''},of: {the: {sentence: {it: '',worked: ''}}}};
function Iterate(obj) {for (prop in obj) {if (obj.hasOwnProperty(prop) && isNaN(prop)) {console.log(prop + ': ' + obj[prop]);Iterate(obj[prop]);}}}Iterate(Dictionary);

如今,您只需添加一个Symbol.iterator方法即可将标准JS对象转换为可迭代对象。然后您可以使用for of循环并直接访问其值,甚至可以在对象上使用扩展运算符。酷。让我们看看如何做到这一点:

var o = {a:1,b:2,c:3},a = [];o[Symbol.iterator] = function*(){var ok = Object.keys(this);i = 0;while (i < ok.length) yield this[ok[i++]];};for (var value of o) console.log(value);// or you can even do likea = [...o];console.log(a);

在ES的最新实现中,您可以使用#0

for (const [key, value] of Object.entries(obj)) { }

Object.entries(obj).forEach(([key, value]) => ...)

如果你只是想遍历这些值,那么使用Object.values:

for (const value of Object.values(obj)) { }

Object.values(obj).forEach(value => ...)

您可以使用Lodash。留档

var obj = {a: 1, b: 2, c: 3};_.keys(obj).forEach(function (key) {...});

女孩和男孩我们在2019年,我们没有那么多时间打字……所以让我们做这个很酷的新花式ECMAScript 2016:

Object.keys(obj).forEach(e => console.log(`key=${e}  value=${obj[e]}`));
let obj = {"a": 3, "b": 2, "6": "a"}
Object.keys(obj).forEach((item) => {console.log("item", obj[item])})
// a// 3// 2

如果运行节点,我建议:

Object.keys(obj).forEach((key, index) => {console.log(key);});

为了进一步完善已接受的答案,值得注意的是,如果你用var object = Object.create(null)实例化对象,那么object.hasOwnProperty(property)将触发TypeError。所以为了安全起见,你需要像这样从原型中调用它:

for (var property in object) {if (Object.prototype.hasOwnProperty.call(object, property)) {// do stuff}}

如果您的环境支持ES2017,那么我会推荐Object.entries

Object.entries(obj).forEach(([key, value]) => {console.log(`${key} ${value}`);});

MozillasObject.entries()留档:

Object.entries()方法返回给定对象自己的数组可枚举属性[键,值]对,顺序与由for… in循环提供(不同之处在于for-in循环也枚举原型链中的属性)。

基本上使用Object.entries我们可以放弃旧的为…在循环所需的以下额外步骤:

// This step is not necessary with Object.entriesif (object.hasOwnProperty(property)) {// do stuff}

上面的答案有点烦人,因为它们没有解释在确保它是一个对象后在for循环中做什么:你不要直接访问它!你实际上只交付了你需要应用到OBJ的密钥:

var obj = {a: "foo",b: "bar",c: "foobar"};
// We need to iterate the string keys (not the objects)for(var someKey in obj){// We check if this key exists in the objif (obj.hasOwnProperty(someKey)){// someKey is only the KEY (string)! Use it to get the obj:var myActualPropFromObj = obj[someKey]; // Since dynamic, use [] since the key isn't literally named "someKey"
// NOW you can treat it like an objvar shouldBeBar = myActualPropFromObj.b;}}

这都是ECMA5安全的。甚至可以在像Rhino这样的蹩脚JS版本中工作;)

多米尼克的答案是完美的,我只是更喜欢这样做,因为它更清晰阅读:

for (var property in obj) {if (!obj.hasOwnProperty(property)) continue;
// Do stuff...}
Object.keys(obj).forEach(key =>console.log(`key=${key} value=${obj[key]}`));

添加ES2015对Reflect.ownKeys(obj)的使用,并通过迭代器迭代属性。

例如:

let obj = { a: 'Carrot', b: 'Potato', Car: { doors: 4 } };

可以通过

// logs each keyReflect.ownKeys(obj).forEach(key => console.log(key));

如果您想直接迭代对象键的值,您可以定义一个iterator,就像JavaS的字符串、数组、类型化数组、Map和Set的默认迭代器一样。

JS将尝试通过默认迭代器属性进行迭代,该属性必须定义为Symbol.iterator

如果您希望能够迭代所有对象,您可以将其添加为Object的原型:

Object.prototype[Symbol.iterator] = function*() {for(p of Reflect.ownKeys(this)){ yield this[p]; }}

这将使您能够使用for… of循环遍历对象的值,例如:

for(val of obj) { console.log('Value is:' + val ) }

注意:在撰写本答案时(2018年6月),除了IE之外,所有其他浏览器都支持生成器和for...of迭代Symbol.iterator

虽然顶级答案是正确的,但这是一个替代用例,即如果您正在迭代一个对象并希望最终创建一个数组。使用.map而不是forEach

const newObj = Object.keys(obj).map(el => {//ell will hold keys// Getting the value of the keys should be as simple as obj[el]})
if (typeof obj === 'object' && obj !== null) {Object.keys(obj).forEach(key => {console.log("\n" + key + ": " + obj[key]);});}
// *** Explanation line by line ***
// Explaining the bellow line// It checks if obj is neither null nor undefined, which means it's safe to get its keys.// Otherwise it will give you a "TypeError: Cannot convert undefined or null to object" if obj is null or undefined.// NOTE 1: You can use Object.hasOwnProperty() instead of Object.keys(obj).length// NOTE 2: No need to check if obj is an array because it will work just fine.// NOTE 3: No need to check if obj is a string because it will not pass the 'if typeof obj is Object' statement.// NOTE 4: No need to check if Obj is undefined because it will not pass the 'if type obj is Object' statement either.if (typeof obj === 'object' && obj !== null) {
// Explaining the bellow line// Just like in the previous line, this returns an array with// all keys in obj (because if code execution got here, it means// obj has keys.)// Then just invoke built-in javascript forEach() to loop// over each key in returned array and calls a call back function// on each array element (key), using ES6 arrow function (=>)// Or you can just use a normal function ((key) { blah blah }).Object.keys(obj).forEach(key => {
// The bellow line prints out all keys with their// respective value in obj.// key comes from the returned array in Object.keys(obj)// obj[key] returns the value of key in objconsole.log("\n" + key + ": " + obj[key]);});}

检查类型

您可以通过以下方式检查propt如何表示对象属性

typeof propt

发现它只是一个字符串(属性的名称)。由于#0 js“内置”循环的工作方式,它会出现对象中的每个属性。

var obj = {name: "Simon",age: "20",clothing: {style: "simple",hipster: false}}
for(var propt in obj){console.log(typeof propt,  propt + ': ' + obj[propt]);}

您可以使用for...inforEach循环访问对象的嵌套属性。

对于……在:

for (const key in info) {console.log(info[key]);}

对于每个:

Object.keys(info).forEach(function(prop) {console.log(info[prop]);// cities: Array[3], continent: "North America", images: Array[3], name: "Canada"// "prop" is the property name// "data[prop]" is the property value});

如果你只是想迭代到map属性值,那么洛达什有_.mapValues

const obj = {a: 2,b: 3}const res = _.mapValues(obj, v => v * 2)console.log(res)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>

简单明了的方法来实现这一点,在现代JS中,无需迭代原型,是这样的:

Object.prototype.iterateProperties = ((callback) => {Object.keys(obj).filter(key => obj.hasOwnProperty(key)).forEach((key) => {callback(key, obj[key]);});});

解释

这段代码在所有对象的原型中创建了一个函数-意味着每个Object实例都可以访问的函数。该函数迭代对象的所有属性并运行一个回调函数,该函数为对象中的每个属性获取(key, value)

使用示例

obj.iterateProperties((key, value) => console.log(key + ': ' + value));