在JS刚出来的时候,想要遍历一个数组,可以像下面这样:
1 2 3
| for (var i = 0; i < array.length; i++) { conosole.log(array[i]) }
|
forEach
在ES5之后,新加了一个forEach
方法:
1 2 3
| array.forEach(function (item) { console.log(item) })
|
forEach
的写法比原来的for
循环简洁,但是在其内部,却不能使用break
和return
结束循环以及continue
跳过循环,比如:
1 2 3 4 5 6 7
| [1, 2, 3].forEach(function(item){ if(item === 2){ return } console.log(item) })
|
for…in
ES5中,还有一个for...in
循环,其用法如下:
1 2 3
| for (var index in array) { console.log(array[index]) }
|
但是,for...in
有以下几个特点:
- 枚举的索引
index
是字符型,不能直接进行数字运算,如:
1 2 3 4 5
| var sum = 0 for (var index in [1, 2, 3]) { sum += index } console.log(sum)
|
- 会将原型对象也一起枚举出来,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {};
var arr = [3, 5, 7]; arr.foo = 'bar';
for (var i in arr) { console.log(i); }
|
如果不想枚举出原型对象,可以配合使用hasOwnProperty
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {};
var arr = [3, 5, 7]; arr.foo = 'bar';
for (var i in arr) { if (arr.hasOwnProperty(i)) { console.log(i) } }
|
- 循环出来的属性顺序如下:先遍历出整数属性(integer properties,按照升序),然后其他属性按照创建时候的顺序遍历出来。
整数属性满足 String(Math.trunc(Number(prop)) === prop
如
“49” 是整数属性,因为 String(Math.trunc(Number('49'))
的结果还是 “49”。
“+49” 不是整数属性,因为 String(Math.trunc(Number('+49'))
的结果是 “49”,不是 “+49”。
“1.2” 不是整数属性,因为 String(Math.trunc(Number('1.2'))
的结果是 “1”,不是 “1.2”。
比如:
1 2 3 4 5 6 7 8 9 10
| var codes = { "49": "Germany", "41": "Switzerland", "44": "Great Britain", "1": "USA" }
for(var code in codes) { console.log(code) }
|
for…of
在ES6中,新加了一个for...of
循环,其用法如下:
1 2 3
| for (var value of array) { console.log(value) }
|
与前面几种方式比较,for...of
是循环数组元素最简洁的方法,避免了for...in
的几个不足,同时也能够使用return
、break
、continue
for...of
能够使用的范围包括了数组、Set
、Map
、字符串、类数组对象(如arguments
、DOM NodeList
对象)、 Generator
对象。
数组
for...of
能够直接使用在数组上,其遍历得到的是键值,而不像for...in
一样得到的是键名:
1 2 3 4 5 6 7 8 9
| var arr = ['a', 'b', 'c', 'd']
for (var index in arr) { console.log(index) }
for (var value of arr) { console.log(value) }
|
同时,for...of
只会遍历数组的数字索引的属性,而for...in
会遍历所有属性:
1 2 3 4 5 6 7 8 9 10
| var arr = [3, 5, 7] arr.foo = 'bar'
for (var index in arr) { console.log(index) }
for (var value of arr) { console.log(value) }
|
Set、Map
Set、Map在使用for...of
进行遍历的时候,顺序是按照各个成员添加到数据结构中的顺序。另外,Set 遍历时,返回的是一个值,而 Map 遍历时,返回的是一个数组,该数组的两个成员分别为当前 Map 成员的键名和键值。
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
| var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]) for (var e of engines) { console.log(e) }
var es6 = new Map() es6.set("edition", 6) es6.set("committee", "TC39") es6.set("standard", "ECMA-262") for (var [name, value] of es6) { console.log(name + ": " + value) }
for (var pair of es6) { console.log(pair) }
|
字符串
在使用for...of
遍历字符串时,还能够正确的识别Unicode编码:
1 2 3 4 5 6
| for (var chr of "😺😲") { console.log(chr) } for (var chr in "😺😲") { console.log(chr) }
|
类数组对象
类数组对象的遍历方法也和数组一样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| let paras = document.querySelectorAll("p");
for (let p of paras) { p.classList.add("test"); }
function printArgs() { for (let x of arguments) { console.log(x); } } printArgs('a', 'b');
|
普通对象
for...of
并不能像for...in
一样直接遍历普通对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var es6 = { edition: 6, committee: "TC39", standard: "ECMA-262" }
for (var e in es6) { console.log(e) }
for (var e of es6) { console.log(e) }
|
解决方法有两种,一是使用Object.entries
/Object.keys
/Object.values
方法由普通对象生成键值对/键名/键值数组,然后遍历这个数组:
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
| var es6 = { edition: 6, committee: "TC39", standard: "ECMA-262" } for (var e of Object.entries(es6)) { console.log(e) }
for (var e of Object.keys(es6)) { console.log(e + ': ' + es6[e]) }
for (var e of Object.values(es6)) { console.log(e) }
|
另一种是使用Generator
函数将对象包装一下:
1 2 3 4 5 6 7 8 9 10 11 12
| function* entries(obj) { for (let key of Object.keys(obj)) { yield [key, obj[key]]; } }
for (let [key, value] of entries(obj)) { console.log(key, '->', value); }
|
参考
- ES6 In Depth: Iterators and the for-of loop
- Iterator 和 for…of 循环
- http://javascript.info/object#the-for-in-loop