参考MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols数据结构
可迭代协议容许 JavaScript 对象去定义或定制它们的迭代行为, 例如(定义)在一个 for..of 结构中什么值能够被循环(获得)。一些内置类型都是内置的可迭代类型而且有默认的迭代行为, 好比 Array or Map, 另外一些类型则不是 (好比Object) 。
为了变成可迭代对象, 一个对象必须实现 @@iterator 方法, 意思是这个对象(或者它原型链 prototype chain 上的某个对象)必须有一个名字是 Symbol.iterator 的属性。
当一个对象须要被迭代的时候(好比开始用于一个for..of循环中),它的@@iterator方法被调用而且无参数,而后返回一个用于在迭代中得到值的迭代器函数
该迭代器协议定义了一种标准的方式来产生一个有限或无限序列的值,而且当全部的值都已经被迭代后,就会有一个默认的返回值。
当一个对象只有知足下述条件才会被认为是一个迭代器:
它实现了一个 next() 的方法而且拥有如下含义
返回一个对象的无参函数,被返回对象拥有两个属性:this
done
(boolean)prototype
value
- 迭代器返回的任何 JavaScript 值。done 为 true 时可省略。next 方法必需要返回一一个对象,该对象有两个必要的属性: done和value,若是返回一个非对象值(好比false和undefined) 会展现一个 TypeError
("iterator.next() returned a non-object value") 的错误code
var myIterator = { next: function() { // ... }, [Symbol.iterator]: function() { return this } }
原生具有 Iterator 接口的数据结构以下。对象
// for...of会获取可迭代对象的[Symbol.iterator](),对该迭代器逐次调用next() // 直到迭代器返回对象的done属性为true时,遍历结束 for (let value of ["a", "b", "c"]) { console.log(value); }
/* 这是一个手写的迭代器(Iterator) 知足迭代器协议的对象。 迭代器协议: 对象的next方法是一个无参函数,它返回一个对象,该对象拥有done和value两个属性: */ 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 }; }, }; }
一个良好的迭代即实现了迭代器协议,又实现了可迭代协议,方式就是可迭代协议返回的是自身接口
/* 使迭代器可迭代 makeIterator函数生成的迭代器并无实现可迭代协议 因此不能在for...of等语法中使用。 能够为该对象实现可迭代协议,在[Symbol.iterator]函数中返回该迭代器自身 重新名了下函数名称createIterator */ function createIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex < array.length ? { value: array[nextIndex++], done: false } : { value: undefined, done: true }; }, [Symbol.iterator]: function () { console.log("返回的迭代器:",this) return this // 注意这里是对象调用模式,this指向的就是上层的对象,迭代器 } }; } var iterator = createIterator([1, 2, 3]); console.log(...iterator)
上面的函数看出,手动写个iterator
太麻烦了,因此ES6
推出generator
,方便建立iterator
。也就是说,generator
就是一个返回值为迭代器iterator
的函数。(感受就是咱们上面函数的语法糖)
生成器对象既是迭代器,又是可迭代对象ip
function *aGeneratorfunction(){ yield 1 yield 2 yield 3 }; var aGeneratorObject = aGeneratorfunction() // 知足迭代器协议,是迭代器 aGeneratorObject.next() // {value: 1, done: false} aGeneratorObject.next() // {value: 2, done: false} aGeneratorObject.next() // {value: 3, done: false} aGeneratorObject.next() // {value: undefined, done: true} // [Symbol.iterator]是一个无参函数,该函数执行后返回生成器对象自己(是迭代器),因此是可迭代对象 aGeneratorObject[Symbol.iterator]() === aGeneratorObject // true // 能够被迭代 var aGeneratorObject1 = aGeneratorfunction() [...aGeneratorObject1] // [1, 2, 3]
遍历返回对象的done值为true时迭代即结束,不对该value处理(return会把done置为done)原型链
function *createIterator() { yield 1; return 42; yield 2; } let iterator = createIterator(); iterator.next(); // {value: 1, done: false} iterator.next(); // {value: 42, done: true} iterator.next(); // {value: undefined, done: true}
let iterator1 = createIterator(); console.log(...iterator); // 1
function* g1() { yield 1; yield 2; } function* g2() { yield* g1(); yield* [3, 4]; yield* "56"; yield* arguments; } var generator = g2(7, 8); console.log(...generator); // 1 2 3 4 "5" "6" 7 8