其余章节请看:javascript
es6 快速入门 系列html
let colors = ['red', 'blue', 'green', 'yellow'] for(let i = 0, len = colors.length; i < len; i++){ console.log(colors[i]) }
上面是一段标准的 for 循环代码,变过变量 i 来跟踪 colors 的索引,虽然语法简单,但若是将多个循环嵌套则须要跟踪多个变量,代码复杂度会大增,一不当心就错误的使用了其余 for 循环的跟踪变量,致使程序出错。迭代器的出现旨在消除这种复杂性并减小循环中的错误java
使用迭代器优化上述问题,请看代码:es6
let colors = ['red', 'blue', 'green', 'yellow'] for(let color of colors){ console.log(color) // 依次输出:red blue green yellow }
每一个集合(数组、Map和Set)类型都有一个默认的迭代器,在 for-of 循环中,若是没有显示指定则使用默认迭代器数组
关于迭代器是什么,生成器是什么,这里的数组、for-of和迭代器三者之间的关系又是什么,函数
全部这些疑问都能在下面的补充章节中找到解答优化
下面咱们用 es5 建立一个迭代器:es5
function createIterator(items){ let i = 0; let len = items.length; return { next: function(){ const result = { value: items[i], done: i++ >= len } return result; } } } let iterator = createIterator(['a', 'b', 'c']) console.log(iterator.next()) // { value: 'a', done: false } console.log(iterator.next()) // { value: 'b', done: false } console.log(iterator.next()) // { value: 'c', done: true } console.log(iterator.next()) // { value: undefined, done: true }
迭代器是一个特殊的对象,它有专门为迭代过程而设计的专有接口,全部的迭代器都有 next() 方法,每次调用 next() 都返回一个结果对象。结果对象有两个属性:一个是value,表示下一个将要返回的值;另外一个是done,是一个布尔值类型的值,当没有更多返回数据时返回true设计
上面这个示例很复杂,es6 中迭代器的编写规则也很复杂,因此 es6 引入生成器,让建立迭代器的过程变得简单code
生成器是一种返回迭代器的函数。经过 function 关键字后面的星号(*)来表示,函数中会用到新的关键字 yield。
下面咱们用生成器重写上面的 createIterator() 方法:
// 星号* 能够紧挨着 function 关键字,也能够在中间加空格 function *createIterator(items){ for(let i = 0, len = items.length; i < len; i++){ yield items[i] } } let iterator = createIterator(['a', 'b', 'c']) console.log(iterator.next()) // { value: 'a', done: false } console.log(iterator.next()) // { value: 'b', done: false } console.log(iterator.next()) // { value: 'c', done: false } console.log(iterator.next()) // { value: undefined, done: true }
createIterator()前面的星号代表它是一个生成器;yield 是 es6 中的新特性,能够经过它来指定调用迭代器的 next() 方法时的返回值和返回顺序。
生成器最有趣的大概是,每次执行完 yield 语句后,函数会自动中止执行。
yield只能在生成器内部使用。下面例子中,从字面上看,yield 确实是在生成器内部,可是它与 return 同样,两者都不能穿透函数边界。
function *createIterator(items){ items.forEach(function(){ yield 1 // 报错 }) }
注:不能用箭头函数建立生成器
首先来回答上面遗留的问题:数组、for-of 和迭代器三者之间的关系是什么?
let colors = ['red', 'blue', 'green', 'yellow'] for(let color of colors){ console.log(color) // 依次输出:red blue green yellow }
es6中,全部的集合(数组、Map及Set)和字符串都是可迭代对象。一个对象若是有与之对应的迭代器,那么它就是可迭代对象;for-of 循环每执行一次都会调用可迭代对象的 next() 方法,并将迭代器返回的结果对象中的 value 存储在一个变量中,循环将持续到返回对象的 done 属性的值为 true。
三者之间的关系这就很清楚了,数组有本身的迭代器,for-of 会循环迭代器
es6中的可迭代对象具备 Symbol.iterator 属性,执行 Symbol.iterator 指定的函数会返回一个做用于该对象的迭代器,以数组为例:
let arr = [11, 22] let iterator = arr[Symbol.iterator]() console.log(iterator.next()) // { value: 11, done: false } console.log(iterator.next()) // { value: 22, done: false } console.log(iterator.next()) // { value: undefined, done: true }
注:若是将 for-of 语句用于不可迭代对象、null 或 undefined 将会致使程序报错
为了更好的访问数据,es6给数组、Set和Map都内建了如下三种迭代器:
let arr = [11, 22] for(let entry of arr.entries()){ // 依次输出:[ 0, 11 ] [ 1, 22 ] console.log(entry) } for(let key of arr.keys()){ // 依次输出:0 1 console.log(key) }
每种集合都有一个默认的迭代器,在 for-of 循环中,若是没有显示指定则使用默认的迭代器。数组和 Set 的默认迭代器是 values() 方法,Map 的默认迭代器是 entries() 方法
let arr = [11, 22] for(let value of arr.values()){ // 依次输出:11 22 console.log(value) } // 等同于 let arr = [11, 22] for(let value of arr){ // 依次输出:11 22 console.log(value) }
自从 es6 添加了迭代器,DOM 中的 NodeList 类型也拥有的默认迭代器,其行为与数组的默认迭代器彻底一致
其余章节请看: