迭代器是咱们咱们平时接触不少的一个特性es6
当咱们遍历数组、字符串或者使用解构赋值、对象展开运算符时都会用到迭代器协议相关内容数组
顾名思义,就是让对象支持被迭代的协议promise
当咱们执行如下代码时,能够明确知道什么值能够被循环获得异步
let a = [1,2,3]
for(let i of a) {
console.log(i) // 1,2,3
}
复制代码
如何支持可迭代协议呢?
对象(或者它原型链上的某个对象)必须有一个名字是 Symbol.iterator 的属性async
Symbol.iterator : 提供一个无参函数, 返回的对象实现迭代器协议函数
迭代器协议定义了如何产生和返回迭代器函数的结果测试
实现迭代器协议的对象至少应该包含一个next方法ui
next方法:
提供一个对象的无参函数,返回的对象拥有两个属性:
done: boolean 不提供则默认是false
value: 用于迭代时获取的对象this
验证迭代对象中的next方法spa
let a = [1,2,3]
var aIt = a[Symbol.iterator]()
aIt.next()
//{value: 1, done: false}
aIt.next()
//{value: 2, done: false}
aIt.next()
//{value: 3, done: false}
aIt.next()
//{value: undefined, done: true}
复制代码
next方法用于依次返回用于迭代的对象,咋一看,这不就是 generator的next方法吗
var c={a:1,1:2,c:4,b:5}
for(let i of c) {
console.log(c)
}
//Uncaught TypeError: c is not iterable at <anonymous>:2:14
复制代码
接下里咱们按照上述协议内容将c对象扩展成支持for...of遍历, 首先实现可迭代协议 即为对象添加Symbol.iterator属性
c[Symbol.iterator] = function(){
return {}
}
复制代码
如何实现迭代器协议? 即在return中返回包含next方法的对象
c[Symbol.iterator] = function(){
return {
_i:0,
next() {
let keys = Object.keys(c)
if(this._i<keys.length){
console.log("调用iterator-next:"+i)
return {value: keys[this._i++],done: false}
}else {
return {done: true, value:undefined}
}
}
}
}
复制代码
测试调用
for(let i of c){console.log(i)}
//1 a c b
复制代码
注: 以上实现中 next方法 this对象指向的是next返回对象
var c={a:1,1:2,c:4,b:5}
function* ci() {
let keys = Object.keys(c),i=0
while(i<keys.length){
yield keys[i++]
}
}
c[Symbol.iterator] = ci
复制代码
调用测试
for(let i of c){console.log(i)}
// 1 a c b
复制代码
为何能够使用generator实现
1.(MDN)调用一个生成器函数并不会立刻执行它里面的语句,而是返回一个这个生成器的 迭代器 (iterator )对象。当这个迭代器的 next() 方法被首次(后续)调用时,其内的语句会执行到第一个(后续)出现yield的位置为止,yield 后紧跟迭代器要返回的值。或者若是用的是 yield*(多了个星号),则表示将执行权移交给另外一个生成器函数(当前生成器暂停执行)
2. cig = new ci()// generator对象。 cig[Symbol.iterator]().next === cig.next
Object.prototype[Symbol.iterator] = function(){
var i=0;
return {next:() =>{
var keys = Object.keys(this)
if(i< keys.length){
return {value: keys[i++],done:false}
}else{
return {done: true}
}
}
}
}
复制代码
测试
var a = {b:1}
for(let i of a){console.log(i)}
// b
for(let i in a){console.log(i)}
// b
复制代码
let a = [1,2,3]
for(let i of a) {
console.log(i)
}
//1
//2
//3
复制代码
var b = {a:1,1:2,c:4,b:5}
[...b]
// Uncaught TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
复制代码
而对上面咱们修改的对象C执行如下代码
[...c]
// ["1", "a", "c", "b"]
复制代码
function* a(){
yield* c
}
var ac = a()
ac.next()
//{value: "1", done: false}
ac.next()
//{value: "a", done: false}
ac.next()
//{value: "c", done: false}
ac.next()
//{value: "b", done: false}
ac.next()
//{value: undefined, done: true}
复制代码
借助对象C的console语句观察解构赋值的过程
[a1,b1] = c
// 调用iterator-next:0
// 调用iterator-next:1
// a1: 1 b1: a
复制代码
以上就是迭代协议相关内容及运用
发现了Symbol.iterator属性的神奇之处,忍不住又看看了Symbol其余的数据, 发现又一个叫asyncIterator的属性
参考iterator, 那就是定义了一个异步可迭代对象了吧 ~_~
用于被for await...of 语句循环使用
(注: for await...of 可用于遍历同步或异步实现迭代器协议的对象)
同iterator,须要含义Symbol.asyncIterator属性, 提供返回一个无参函数,返回一个包含next方法的对象
暂时可能没有想到什么必须合适的场景,那就无病呻吟一下吧,↓
先验证下for await...of
var a = [Promise.resove(1),Promise.resolve(2),Promise.resolve(3)]
for(let i of a){
console.log(i)
}
// promise * 3
for await(let i of a) {
console.log(i)
}
// 1,2,3
复制代码
构造一个异步可迭代对象
var asyncIterable = {
[Symbol.asyncIterator]() {
return {
i: 0,
next() {
if (this.i < 3) {
return Promise.resolve({ value: this.i++, done: false });
}
return Promise.resolve({ done: true });
}
};
}
};
for await (let num of asyncIterable) {
console.log(num);
}
// 0,1,2
复制代码
目前还木有实现了asyncIterator内置属性的对象
注: 非标准属性,只在FF下有实现,慎用
Iterator 函数返回一个对象,它实现了遗留的迭代协议,而且迭代了一个对象的可枚举属性。
var a = {a: 1,1: 2,c:3,b:4};
for (var [name, value] of Iterator(a)) {
console.log(name, value);
}
// 1,2 a,1 c,3 b,4
复制代码