ES6 Iterator 和 for...of 循环

一. for...of 循环

1.for...of

(1).基本使用

const arr = ['red', 'green', 'blue'];   
for(let v of arr) {  
    console.log(v); // red green blue  
}  
(2).注意这几点:
A.这是目前遍历数组最简洁和直接的语法;
B.它避免了for-in的所有缺陷;
C.与forEach()不一样,它支持break,continue和return。
for-in循环用于遍历对象属性。

for-of循环用于遍历数据——比如数组中单值。

(3).其它集合也支持for-of

for-of循环不仅仅是为遍历数组而设计的。基本上所有类数组对象都适用,比如DOM NodeListS。

也能用在字符串上,它将字符串当做一个Unicode字符序列:

for (var chr of "abc"){
  console.log(chr); //依次弹出a,b,c
}

A.Set集合

var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
  console.log(e);
}
// Gecko
// Trident
// Webkit

B.Map集合:它里面的数据由键值对组成,所以你需要使用destructuring将“键”和“值”解构为两个独立的变量:

for (var [key, value] of phoneBookMap) { 
    console.log(key + "'s phone number is: " + value); 

}

如下面例子:

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

C.数组

数组原生具备iterator接口(即默认部署了Symbol.iterator属性),for...of循环本质上就是调用这个接口产生的遍历器,可以用下面的代码证明。

const arr = ['red', 'green', 'blue'];

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

const obj = {};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);

for(let v of obj) {
  console.log(v); // red green blue
}
上面代码中,空对象obj部署了数组arr的Symbol.iterator属性,结果obj的for...of循环,产生了与arr完全一样的结果。

2.与for..in 比较

var  a=['A','B','C'];
var  s= new Set(['A','B','C']);
var  m= new Map([[1,'x'],[2,'y'],[3,'z']]);
a.name='hell0';

// 遍历数组	
for(var x in a){
	console.log(x)//输出  0 1 2
}
for(var x of a){
	console.log(x)//输出A B C
}

// 遍历Set集合
for(var x in s){
	console.log(x)//不起作用
}
for(var x of s){
	console.log(x)//输出A B C
}

// 遍历Map集合
for(var x in m){
	console.log(x[0]+"="+x[1])//不起作用
}
for(var x of m){
	console.log(x[0]+"="+x[1]);//输出1=x  2=y   3=z
}
for...in由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组也是一个对象,数组中的每个元素的索引被视为属性名称,所以我们可以看到使用for...in循环Array数组时,拿到的其实是每个元素的索引。
var  a=['A','B','C'];
a.name='hell0';

// 遍历数组
for(var x in a){
	console.log(x)//输出 0 1 2 3 name
}
for(var x of a){
	console.log(x)//输出 A B C
}
console.log("a数组:"+a)//a数组:A,B,C
如上所示,当我们为a多手动添加一个属性name的时候,for...in循环会把name属性也包括在内,而Array的length属性却不包括在内。

for...of循环则不存在上述的问题,它只循环集合本身的元素。这就是为什么引入for...of循环。

总而言之,for-in语法是被设计来遍历普通的“键值对”对象的,不适合用在数组上。

二.Iterator

1.概念

遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

2.作用:
①为各种数据结构,提供一个统一的、简便的访问接口
②使得数据结构的成员能够按某种次序排列
③ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费
3.Iterator的遍历过程:
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。

var it = makeIterator(['a', 'b']);

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}


it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

2.默认 Iterator接口

Iterator 接口的目的, 就是为所有数据结构, 提供了一种统一的访问机制, 即for...of循环( 详见下文)。 当使用for...of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。

ES6 规定, 默认的 Iterator 接口部署在数据结构的Symbol.iterator属性, 或者说, 一个数据结构只要具有Symbol.iterator属性, 就可以认为是“ 可遍历的”( iterable)。 调用Symbol.iterator方法, 就会得到当前数据结构默认的遍历器生成函数。 Symbol.iterator本身是一个表达式, 返回 Symbol 对象的iterator属性, 这是一个预定义好的、 类型为 Symbol 的特殊值, 所以要放在方括号内( 请参考 Symbol 一章)。

const obj = {
  [Symbol.iterator] : function () {
    return {
      next: function () {
        return {
          value: 1,
          done: true
        };
      }
    };
  }
};

在 ES6 中, 有三类数据结构原生具备 Iterator 接口: 数组、 某些类似数组的对象、 Set 和 Map 结构。可以覆盖原生的Symbol.iterator方法,达到修改遍历器行为的目的。

let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
const obj = {
  [Symbol.iterator] : function () {
    return {
      next: function () {
        return {
          value: 1,
          done: true
        };
      }
    };
  }
};
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }

三.参考

1.【探秘ES6】系列专栏(二):迭代器和for-of循环

2.沅一峰 Iterator 和 for...of 循环

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值