可迭代协议(The iterable protocol) 和 迭代器协议(The iterator protocol)是对 ECMAScript 2015 的补充,不是新的内置或语法,仅仅是协议。能够被任何遵循某些约定的对象来实现。函数
可迭代协议容许 JavaScript 对象去定义或者定制它们的迭代行为。this
一些内置类型是可迭代,例如 Array,TypeArray,Map,Set,String,在 for...of 结构中能够循环遍历值,而 Object 就不是。prototype
为了变成可迭代对象,一个对象必须实现 @@iterator 方法, 意思是这个对象(或者它原型链 prototype chain 上的某个对象)必须有一个名字是 Symbol.iterator 的属性:code
Property | Value |
---|---|
[Symbol.iterator] | 无参函数,该函数返回一个对象,该对象符合迭代器协议 |
迭代器协议定义了一种标准的方式来产生有限或无限序列的值对象
当一个对象实现了 next() 方法,而且符合以下定义,则该对象就是一个迭代器对象。ip
属性 | 值 |
---|---|
next | 一个无参函数,返回一个对象,该对象拥有两个属性 done 和 value |
迭代器返回的任何 JavaScript 值,当 done 为 true,可忽略。原型链
next 方法必须是返回包含 done 和 value 属性的对象,若是非对象(类如 false, undefined)返回,将会抛出 TypeErrorget
const iterableObj = {} iterableObj[Symbol.iterator] = function* () { yield 1 yield 2 yield 3 } console.log([...iterableObj])
许多 APIs 接受可迭代对象做为参数,例如 Map([iterable]),WeakMap([iterable]),Set([iterable]),WeakSet([iterable])generator
const myObj = {} new Map([[1, 'a'], [2, 'b'], [3, 'c']]).get(2) // "b" new WeakMap([[{}, 'a'], [myObj, 'b'], [{}, 'c']]).get(myObj) // "b" new Set([1, 2, 3]).has(3) // true new Set('123').has('2') // true new WeakSet(function* () { yield {} yield myObj yield {} }()).has(myObj) // true
一些语句或者表达式可用于可迭代对象,例如 for...of 循环,spread operator,yield*,destructuring assignment。原型
// for...of for (let i of [1, 2, 4]) { console.log(i) // 1 // 2 // 4 } // spread operator console.log([...'abc']) // ["a", "b", "c"] // yield* function* gen() { yield* ['a', 'b', 'c'] } console.log(gen().next()) // {value: "a", done: false} // destructuring assignment [a, b] = new Set(['a', 'b']) console.log(a) // a
function makeIterator(array) { let nextIndex = 0 return { next() { return nextIndex < array.length ? { value: array[nextIndex++], done: false } : { done: true } } } } const it = makeIterator(['a', 'b']) console.log(it.next()) // {value: "a", done: false} console.log(it.next()) // {value: "a", done: false} console.log(it.next()) // {done: true}
function* makeSimpleGenerator(arr) { let nextIndex = 0 while (nextIndex < array.length) { yield array[nextIndex++] } } const it = makeSimpleGenerator(['a', 'b']) console.log(it.next()) // {value: "a", done: false} console.log(it.next()) // {value: "a", done: false} console.log(it.next()) // {value: undefined, done: true}
class SimpleIterator { constructor(data) { this.data = data this.index = 0 } [Symbol.iterator]() { return { next: () => { return this.index < this.data.length ? { value: this.data[this.index++], done: false } : { done: true } } } } } const simple = new SimpleIterator([1, 3, 9]) for (let i of simple){ console.log(i) // 1 3 9 }
从上面的示例能够看出,generator 是比较特殊的,generator 既是一个 生成器对象,又是一个 可迭代对象!
const generatorObj = function* () { yield 1 yield 2 yield 3 }() console.log(typeof generatorObj.next) // function console.log(typeof generatorObj[Symbol.iterator]) // function console.log(generatorObj[Symbol.iterator]() === generatorObj) // true
文章如有纰漏,欢迎你们提问交流!