关于javascript:迭代对象属性

Iterate through object properties

1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
    name:"Simon",
    age:"20",
    clothing: {
        style:"simple",
        hipster: false
    }
}

for(var propt in obj){
    console.log(propt + ': ' + obj[propt]);
}

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


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

1
2
3
4
5
for (var property in object) {
    if (object.hasOwnProperty(property)) {
        // do stuff
    }
}

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

hasOwnProperty只是检查这是否是一个特定于这个类的属性,而不是从基类继承的属性。


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

1
2
3
4
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循环更好(也更可读)。

这些浏览器支持它:

  • 火狐(Gecko):4(2.0)
  • 铬:5
  • Internet Explorer:9

有关更多信息,请参阅mozilla developer network object.keys()的参考。


我们是2017年的女孩和男孩,我们没有那么多时间打字……所以让我们来做这个酷的新花式ecmascript 2016:

1
Object.keys(obj).forEach(e => console.log(`key=${e}  value=${obj[e]}`));


它是for...in statement(mdn,ecmascript spec)。

您可以将其理解为"对于obj对象中的每个属性,依次将每个属性分配给propt变量"。


在即将推出的ES版本中,您可以使用Object.entries

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

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

如果只想迭代这些值,那么使用object.values:

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

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


这只是一个for...in循环。查看Mozilla的文档。


jquery允许您现在这样做:

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


多米尼克的回答是完美的,我只是更喜欢这样做,因为阅读起来更干净:

1
2
3
4
5
for (var property in object) {
    if (!object.hasOwnProperty(property)) continue;

    // Do stuff...
}

上面的答案有点烦人,因为在确保它是一个对象之后,它们无法解释您在for循环中所做的操作:您不能直接访问它!实际上,您只收到了应用于obj所需的密钥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 obj
  if (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 obj
    var shouldBeBar = myActualPropFromObj.b;
  }
}

这都是ECMA5安全的。甚至可以在Rame JS版本中工作,比如Rhino;)


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

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

如mozilla object.entries()文档所示:

The Object.entries() method returns an array of a given object's own
enumerable property [key, value] pairs, in the same order as that
provided by a for...in loop (the difference being that a for-in loop
enumerates properties in the prototype chain as well).

基本上,对于object.entries,我们可以放弃旧的for…in循环所需的以下额外步骤:

1
2
3
4
// This step is not necessary with Object.entries
if (object.hasOwnProperty(property)) {
  // do stuff
}

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

例如:

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

可以迭代

1
2
// logs each key
Reflect.ownKeys(obj).forEach(key => console.log(key));

如果要直接迭代对象键的值,可以定义一个iterator,就像javascripts对字符串、数组、类型化数组、映射和设置的默认迭代器一样。

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

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

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

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

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

注意:在编写此答案(2018年6月)时,除了支持Generator和for...of迭代(通过Symbol.iterator)外,所有其他浏览器


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

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

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

1
2
3
4
    for(var propt in obj) {
      console.log(propt);//logs name
      console.log(obj[propt]);//logs"Simon"
    }

您可以看到变量与变量值的区别。相反,for…of循环则相反。

我希望这有帮助。


1
2
3
4
5
6
7
let obj = {"a": 3,"b": 2,"6":"a"}

Object.keys(obj).map((item) => {console.log("item", obj[item])})

// a
// 3
// 2


你可以用木屑。文件

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


1
2
3
Object.keys(obj).forEach(key =>
  console.log(`key=${key} value=${obj[key]}`)
);

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

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


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


现在,只需添加symbol.iterator方法,就可以将标准JS对象转换为可ITerable对象。然后,您可以使用for of循环并直接获取其值,甚至可以对对象使用spread运算符。酷。让我们看看如何做到:

1
2
3
4
5
6
7
8
9
10
11
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 like
a = [...o];
console.log(a);


同时添加递归方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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 yet
                  var alreadyFound = false;
                  for(var i = 0; i < walked.length; i++)
                  {
                    if (walked[i] === obj[property])
                    {
                      alreadyFound = true;
                      break;
                    }
                  }
                  // new object reference
                  if (!alreadyFound)
                  {
                    walked.push(obj[property]);
                    stack.push({obj: obj[property], stack: item.stack + '.' + property});
                  }
                }
                else
                {
                    console.log(item.stack + '.' + property +"=" + obj[property]);
                }
            }
        }
    }
}

用途:

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


如果运行节点,我建议:

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

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

杰西德

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);


我想添加到上面的答案中,因为您可能与JavaScript有不同的意图。JSON对象和JavaScript对象是不同的,您可能希望使用上面提出的解决方案迭代JSON对象的属性,然后感到惊讶。

假设您有一个JSON对象,比如:

1
2
3
4
5
6
7
var example = {
   "prop1":"value1",
   "prop2": ["value2_0", value2_1"],
   "
prop3": {
        "
prop3_1":"value3_1"
    }
}

迭代其"属性"的方法错误:

1
2
3
4
5
6
function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        recursivelyIterateProperties(jsonObject[prop]);
    }
}

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

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

1
2
3
4
5
6
7
8
9
10
11
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]);

            }

     }
}

在循环中..的作用是创建一个新变量(var somevariable),然后将给定对象的每个属性逐个存储在这个新变量(somevariable)中。因此,如果使用块,则可以迭代。考虑下面的例子。

1
2
3
4
5
6
7
8
9
10
11
var obj = {
     name:'raman',
     hobby:'coding',
     planet:'earth'
     };

for(var someVariable in obj) {
  //do nothing..
}

console.log(someVariable); // outputs planet


在这里,我将迭代每个节点并创建有意义的节点名。如果您注意到,instanceof array和instanceof object基本上做了相同的事情(在我的应用程序中,我给出了不同的逻辑)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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]);
            }
        }
    }
}

注意-我受到了恩德雷克·斯韦杰达尔的回答的启发。但是这个解决方案有更好的性能和更少的模糊性


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

1
2
3
4
5
for (var property in object) {
    if (Object.prototype.hasOwnProperty.call(object, property)) {
        // do stuff
    }
}