遍历Array能够采用下标循环,遍历Map和Set就没法使用下标。为了统一集合类型,ES6标准引入了新的iterable类型,Array、Map和Set都属于iteratore类型。
全部的iterator对象都有next()方法,会返回一个结果对象。该结果对象拥有两个属性,value和done.
下面的例子模拟生成iteratores6
var it = makeIterator(['a', 'b']); it.next() // { value: "a", done: false } it.next() // { value: "b", done: false } it.next() // { value: undefined, done: true } function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}; } }; }
上例能够看出,要生成一个iterator很复杂。幸亏ES6专门提供了generator用来生成iterator.数组
generator 是一个返回迭代器的函数,与普通函数不一样的是声明generators函数要在function后面添加"*",同时函数内部使用es6新增长的关键字yield来控制next()方法的返回值。数据结构
// generator 函数 function *createIterator(){ yield 1; yield 2; yield 3; } // 建立迭代器 let iterator = createIterator(); console.log(iterator.next().value); // 1 console.log(iterator.next().value); // 2 console.log(iterator.next().value); // 3 console.log(iterator.next().value); // undefined
从上述代码能够看出每次的yield使用均可以阻止代码的执行,当迭代器调用next()方法后才会继续执行。
也可使用函数表达式的形式建立generator函数。ide
let createIterator = function *(items){ for(let i=0;i<items.length;i++){ yield items[i]; } } let iterator = createIterator([1,2,3]); console.log(iterator.next()); // "{value:1,done:false}" console.log(iterator.next()); // "{value:2,done:false}" console.log(iterator.next()); // "{value:3,done:false}" console.log(iterator.next()); // "{value:undefined,done:true}" console.log(iterator.next()); // "{value:undefined,done:true}"
注意: 关键字yield只能在generator函数内部使用,即便在生成器内部的函数中也不行。以下代码:函数
function *createIterator(items){ items.forEach(function(item){ yield item + 1; }) } let iterator = createIterator([1,2,3]); console.log(iterator.next()); // "Uncaught SyntaxError: Unexpected identifier"
在对象中建立生成器。code
var o = { createIterator: function *(items) { for(let i =0; i<items.length; i++) { yield items[i]; } } }; let iterator = o.createIterator([1,2,3]);
ES6写法:orm
var o = { *createIterator(items) { for(let i =0; i<items.length; i++) { yield items[i]; } } }; let iterator = o.createIterator([1,2,3]);
Iterator 接口的目的,就是为全部数据结构,提供了一种统一的访问机制,即for...of循环。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。
一种数据只要部署了Iterator接口,就认为这种数据是可遍历的(iterable)。默认的Iterator接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具备Symbol.iterator属性,就能够认为是“可遍历的”(iterable)。
Symbol.iterator属性自己是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预约义好的、类型为 Symbol 的特殊值,因此要放在方括号内。对象
const obj={ [Symbol.iterator]: function() { return { next: function() { return { value: 1, done: true } } } } } obj[Symbol.iterator]().next(); // {value: 1, done: true}
上面代码,obj具备Symbol.iterator属性,是可遍历的。执行这个属性,会返回一个遍历器对象。该对象的根本特征就是具备next方法。每次调用next方法,都会返回一个表明当前成员的信息对象,具备value和done两个属性。
Array,Map,Set,String,TypedArray,函数的arguments对象,NodeList对象都具备Iterator接口。能够被for...of遍历。
注意: 对象(Object)没有默认部署 Iterator 接口。索引
let values = [1, 2, 3]; for (let num of values) { console.log(num); // 1 2 3 }
for...of首先调用values数组的Symbol.iterator的方法,获取一个迭代器。而后iterator.next()被调用,迭代器的value属性被读出并放入了num变量。num 变量的值开始为 1 ,接下来是2,最后变成 3 。当结果对象的done变成true,循环就退出了。接口
上例的代码也可采用下面的方法:
let values = [1, 2, 3]; let iter = values[Symbol.iterator](); iter.next(); // {value: 1, done: false} iter.next(); // {value: 2, done: false} iter.next(); // {value: 3, done: false} iter.next(); // {value: undefined, done: true}
ES5中有for...in遍历对象,那么for...in和for...of有什么区别呢?
for ... in循环因为历史遗留问题,它遍历的其实是对象的属性名称。一个Array数组实际上也是一个对象,它的每一个元素的索引被视为一个属性。当咱们手动给Array对象添加了额外的属性后,for ... in循环将带来意想不到的意外效果:
var a = ['A', 'B', 'C']; a.name = 'Hello'; for (var x in a) { console.log(x); // '0', '1', '2', 'name' }
采用for...of的写法
var a = ['A', 'B', 'C']; a.name = 'Hello'; for (var x of a) { console.log(x); // 'A', 'B', 'C' }
结论:for...in遍历的实际是key,而for...of遍历的是value。
let colors = [ "red", "green", "blue" ]; let tracking = new Set([1234, 5678, 9012]); let data = new Map(); data.set("title", "Understanding ES6"); data.set("format", "ebook"); for (let entry of colors.entries()) { console.log(entry); } for (let entry of tracking.entries()) { console.log(entry); } for (let entry of data.entries()) { console.log(entry); }
以上代码输出结果:
[0, "red"] [1, "green"] [2, "blue"] [1234, 1234] [5678, 5678] [9012, 9012] ["title", "Understanding ES6"] ["format", "ebook"]
注意:数组不支持values()
let colors = [ "red", "green", "blue" ]; let tracking = new Set([1234, 5678, 9012]); let data = new Map(); data.set("title", "Understanding ES6"); data.set("format", "ebook"); for (let value of colors.values()) { console.log(value); } for (let value of tracking.values()) { console.log(value); } for (let value of data.values()) { console.log(value); }
以上代码输出结果:
TypeError: colors.values(...)[Symbol.iterator] is not a function 1234 5678 9012 "Understanding ES6" "ebook"
let colors = [ "red", "green", "blue" ]; let tracking = new Set([1234, 5678, 9012]); let data = new Map(); data.set("title", "Understanding ES6"); data.set("format", "ebook"); for (let key of colors.keys()) { console.log(key); } for (let key of tracking.keys()) { console.log(key); } for (let key of data.keys()) { console.log(key); }
以上代码输出结果:
0 1 2 1234 5678 9012 "title" "format"