forEach
数组实例的遍历方法
- const arr=['red', 'green', 'blue'];
- arr.forEach(function(element, index) {
- console.log(element);// red green blue
- console.log(index);// 0 1 2
- });
forEach 这种写法的问题是, 无法中途跳出 forEach 循环, break 命令或 return 命令都不能奏效.
for...in
JavaScript 原有的循环, 只能获得对象的键名, 不能直接获取键值.
- var arr = ['a', 'b', 'c', 'd', 'e'];
- for(let i in arr) {
- console.log(i);//0 1 2 3 4
- }
- for(let index in arr) {
- console.log(arr[index]);// a b c d e
- }
- let es6 = {
- edition: 6,
- committee: "TC-39",
- standard: "ECMA-262"
- };
- for(let e in es6) {
- console.log(e);
- }
- //edition
- //committee
- //standard
for...in 循环有几个缺点:
数组键名是数字, 但是 for...in 循环是以字符串作为键名 "0","1","2" 等
for...in 循环不仅遍历数字键名, 还会遍历手动添加的其它键, 甚至包括原型链上的键.
某些情况下, for...in 循环会以任意顺序遍历键名.
总之, for...in 循环主要是为遍历对象为设计的, 不适用于遍历数组.
for...of
ES6 借鉴 C++,Java,C# 和 Python 语言, 引入了 for...of 循环, 作为遍历所有数据结构的统一的方法. 一个数据结构只要部署了 Symbol.iterator 属性, 就被视为具有 iterator 接口, 就可以用 for...of 循环遍历它的成员. 也就是说, for...of 循环内部调用的是数据结构的 Symbol.iterator 方法. for...of 循环可以使用的范围包括数组, Set 和 Map 结构, 某些类似数组的对象 (比如 arguments 对象, DOM NodeList 对象),Generator 对象以及字符串.
数组原生具有 iterator 接口 (即默认部署了 Symbol.iterator 属性),for...of 循环本质上就是调用这个接口产生的遍历器, 允许遍历获得键值;
- var arr = ['a', 'b', 'c', 'd', 'e'];
- for(let i of arr) {
- console.log(i);//a b c d e
- }
for...of 循环可以代替数组实例的 forEach 方法
for...of 循环调用遍历器接口, 数组的遍历器接口只返回具有数字索引的属性; 这一点与 for...in 也不一样.
- let arr = [1,3,5];
- arr.foo = 'hello';
- for(let i in arr) {
- console.log(i);//'1', '3', '5', 'foo'
- }
- for(let i of arr) {
- console.log(i);//'1', '3', '5'
- }
Set 和 Map 结构也原生具有 Iterator 接口, 可以直接使用 for...of 循环
- var engines = new Set(["Gecko", "Trident", "webkit", "Webkit"]);
- for(var e of engines) {
- console.log(e);
- }
- //Gecko
- //Trident
- //Webkit
- 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);
- }
- //edition: 6
- //committee: TC39
- //standard: ECMA-262
Set 和 Map 遍历的顺序是按照各个成员被添加进数据结构的先后顺序. 其次, Set 结构遍历, 返回的是一个值. Map 结构遍历返回的是一个数组, 该数组的两个成员分别为当前 Map 成员的键名和键值.
for...of 循环, 获得数组的索引, 可以借助数组实例的 entries 方法和 keys 方法.
- let arr = ["a", "b", "c"];
- for(let pair of arr.entries()) {
- console.log(pair);
- }
- //[0, 'a']
- //[1, 'b']
- //[2, 'c']
for...of 遍历类似数组的对象 (String,DOM NodeList,arguments)
- // 字符串
- let str="hello";
- for(let s of str) {
- console.log(s);// h e l l o
- }
- //DOM NodeList 对象
- let paras = document.querySelectorAll("p");
- for(let p of paras) {
- p.classList.add("test");
- }
- //arguments 对象
- function printArgs() {
- for(let x of arguments) {
- console.log(x);
- }
- }
- printArgs('a', 'b');
- //'a'
- //'b'
对字符串来说, for...of 循环还能够正确识别 32 位 UTF-16 字符
- for (let x of 'a\uD83D\uDC0A) {
- console.log(x);
- }
- //'a'
- //'\uD83D\uDC0A'
并不是所有类似数组的对象都具有 Iterator 接口, 一个方法是用 Array.from 方法将其转换为数组
- let arrayLike = [length: 2, 0: 'a', 1: 'b'];
- for(let x of array.from(arrayLike)) {
- console.log(x);
- }
对于普通的对象, for...of 结构不能直接使用, 必须部署 Iterator 接口后才能使用. 一种解决方法是将对象的键名生成一个数组, 然后遍历这个数组:
- for(let key of Object.keys(someObject)) {
- console.log(key + ":" + someObject[key]);
- }
另一个方法是使用 Generator 函数
- 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);
- }
- //a -> 1
- //b -> 2
- //c -> 3
for...of 相对其它遍历方法, 有以下优点:
有着同 for...in 一样简洁的语法, 但是没有 for...in 那些缺点;
不同于 forEach 方法, 它可以与 break,continue 和 return 配合使用
提供了遍历所有数据结构的统一操作接口
- for(var n of fibonacci) {
- if(n>1000)
- break;
- console.log(n);
- }
参考:
Iterator 和 for...of http://es6.ruanyifeng.com/#docs/iterator
来源: http://www.bubuko.com/infodetail-2689698.html