JS循环遍历方法及区别

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
38
[1] const arr = [7, 8, 9];
const obj = {
a: 4,
b: 5,
c: 6
};
[2] for (let v in arr){
console.log(v);
}
// 0, 1, 2
[3 ]for (let v in obj){
console.log(v);
}
// a, b, c
[4] arr.child = 'child';
[5] arr.__proto__.getChild = function () {
return this.child;
};
[6] Array.prototype.parent = 'parent';
[7] for (let v in arr){
console.log(v);
}
// 0, 1, 2, child, getChild, parent
[8]for (let v of arr){
console.log(v);
}
// 7, 8, 9
[9] for (let v of arr.values()){
console.log(v);
}
// 7, 8, 9
[10] for (let v of obj){
console.log(v);
}
// 报错
[11] typeof arr.keys(); // 'object'
arr.keys() instanceof Array; // false
arr.keys() instanceof Object; // true

for in

for in在ES5中便出现了。一般用来遍历对象属性。但也可用于数组遍历,返回的值是数组的索引,因为,严格来说,数组也是一个对象,所对应的属性是每个值的索引。 **for-in只遍历对象自身的和继承的可枚举的属性(摘自 阮一峰ECMAScript 6 入门-对象扩展一章)**。
如[4]、[5]、[6]所示,为数组添加可遍历属性 (所对应描述器descriptor的enumerable属性为true) ,在[7]中用for-in遍历都可遍历出来。

for of

for of为ES6新增遍历方法。其可遍历所有具有 iterator 接口的数据结构。for…of循环内部调用的是数据结构的Symbol.iterator方法(generator函数)。(摘自 阮一峰ECMAScript 6 入门–Iterator 和 for…of 循环一章)。Symbol.iterator方法返回的是一个遍历器,当用for-of去遍历的时候, 自动调用里面的next方法。
如[8], [9]所示,数组原生具备iterator接口(即默认部署了Symbol.iterator属性),for…of循环本质上就是调用这个接口产生的 遍历器。再看?例子 (摘自 阮一峰ECMAScript 6 入门–Iterator 和 for…of 循环一章),对象obj默认调用的遍历器生成器是obj.values即obj[Symbol.iterator] 。

1
2
3
4
5
6
7
8
9
10
11
12
const colorArr = ['red', 'green', 'blue'];
for(let v of colorArr) {
console.log(v);
}
// red green blue
const colorObj = {};
colorObj[Symbol.iterator] = colorArr[Symbol.iterator].bind(colorArr);

for(let v of colorObj) {
console.log(v);
}
// red green blue

总结

所以说,(for in)遍历键名和 (for of)遍历键值,这种说法并不严谨。for in确实是遍历属性,而且更是遍历对象自身的和继承的可枚举的属性。但是,for of遍历键值这种说法便不严谨了,比如说我们一开始在[1]中声明的对象obj,键名为a,b, c; 键值为4,5,6;

按照(for of)遍历键值这种说法,用for of遍历obj应该返回键值4,5,6。可是如[10]所示,程序执行报错了。因为对象默认是没有iterator接口的,我们不可以直接遍历,当我们需要遍历对象的属性时,可以调用Object.keys()返回一个数组,用来遍历所有的键名。当我们需要遍历对象的属性值时,应该调用obj.values()返回一个数组,用来遍历所有的键值。并不是说for-of遍历键值,for-of具体遍历并返回的是什么,是视of后面返回的数组对应是什么。就obj这个对象来说,我们可以遍历obj的键值(Object.values(obj)),也可以遍历obj的键名(Object.keys(obj)),更可以遍历对象的obj的键值对(Object.entires(obj))。
同样。for-of遍历数组,数组是默认具有iterator接口的,即arr.values(),具体遍历并返回的是什么,是视of后面返回的遍历器对象是什么。arr的键值(arr.values()),也可以遍历数组arr的键名(arr.keys()),更可以遍历数组的arr的键值对(arr.entires())。

遍历器对象是一个对象,不是数组。如[11]所示,arr.keys() 是对象Object的实例,并不是数组实例。