Iterator
-
遍历器(Iterator)是一种机制(接口):为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作「for of循环」,依次处理该数据结构的所有成员
-
- 拥有next方法用于依次遍历数据结构的成员
-
- 每一次遍历返回的结果是一个对象 {done:false,value:xxx}
-
done:记录是否遍历完成
-
value:当前遍历的结果
-
拥有Symbol.iterator属性的数据结构(值),被称为可被遍历的,可以基于for of循环处理
-
- 数组
-
- 部分类数组:arguments/NodeList/HTMLCollection...
-
- String
-
- Set
-
- Map
-
- generator object
-
- ...
-
对象默认不具备Symbol.iterator,属于不可被遍历的数据结构
class Iterator {
constructor(assemble) {
let self = this;
self.assemble = assemble;
self.index = 0;
}
next() {
let self = this,
assemble = self.assemble;
if (self.index > assemble.length - 1) {
return {
done: true,
value: undefined
};
}
return {
done: false,
value: assemble[self.index++]
};
}
}
let itor = new Iterator([10, 20, 30, 40]);
console.log(itor.next()); //->{value:10,done:false}
console.log(itor.next()); //->{value:20,done:false}
console.log(itor.next()); //->{value:30,done:false}
console.log(itor.next()); //->{value:40,done:false}
console.log(itor.next()); //->{value:undefined,done:true}
// 让对象也具备迭代器规范
Object.prototype[Symbol.iterator] = function () {
let assemble = this,
keys = Object.keys(assemble)
.concat(Object.getOwnPropertySymbols(assemble)),
index = 0;
return {
next() {
if (index > keys.length - 1) {
return {
done: true,
value: undefined
};
}
return {
done: false,
value: assemble[keys[index++]]
};
}
};
};
let obj = {
name: 'zhufeng',
age: 12,
teacher: 'team'
};
for (let value of obj) {
console.log(value);
}
// 如果是类数组对象,可直接继承数组的Symbol.iterator「JQ也是如此」
let obj = {
0: 10,
1: 20,
2: 30,
length: 3
};
obj[Symbol.iterator] = Array.prototype[Symbol.iterator];
for (let value of obj) {
console.log(value);
}
Generator
生成器对象是由一个generator function返回的,并且它符合可迭代协议和迭代器协议
developer.mozilla.org/zh-CN/docs/…
-
普通函数 VS 生成器函数
-
生成器函数 [[IsGenerator]]:true
-
「把它当做一个实例 proto」
-
普通函数是 Function 的实例,普通函数.proto===Function.prototype
-
生成器函数是 GeneratorFunction 的实例
-
生成器函数.proto===GeneratorFunction.prototype
-
GeneratorFunction.prototype.proto===Function.prototype
-
({}).toString.call(生成器函数) => "[object GeneratorFunction]"
-
「把它作为一个构造函数 prototype」
-
生成器函数不能被new执行 Uncaught TypeError: func is not a constructor
-
当做普通函数执行,返回的结果就是生成器函数的一个实例
-
itor.proto -> func.prototype「空对象,没有constructor」 -> Generator.prototype「constructor:GeneratorFunction」{next/return/throw/Symbol(Symbol.toStringTag): "Generator"} -> 一个具备迭代器规范的对象「Symbol(Symbol.iterator)」 -> Object.prototype
// generator函数:function后面加一个*
function* fn() {
console.log(this);
return 10;
}
fn.prototype.query = function () {};
let gen = fn();
console.log(gen);
// gen.__proto__ -> fn.prototype「query」 -> GeneratorFunction.prototype「next/return/throw/Symbol.toStringTag」-> xxx.prototype「Symbol.iterator」 -> Object.prototype
console.log(typeof fn); //->"function"
console.log(fn instanceof Function); //->true
function* generator() {
console.log('A');
yield 10;
console.log('B');
yield 20;
console.log('C');
yield 30;
console.log('D');
return 100;
}
let itor = generator();
console.log(itor.next()); //->{value:10,done:false}
console.log(itor.next()); //->{value:20,done:false}
console.log(itor.next()); //->{value:30,done:false}
console.log(itor.next()); //->{value:100,done:true}
console.log(itor.next()); //->{value:undefined,done:true}
function* generator() {
console.log('A');
yield 10;
console.log('B');
yield 20;
console.log('C');
return 30;
}
let itor = generator();
console.log(itor.next()); //->{value:10,done:false}
console.log(itor.return('@return')); //->{value:"@return",done:true}
// console.log(itor.throw('@throw'));
console.log(itor.next()); //->{value:undefined,done:true}
// 每一次执行next的传递的值,是作为上一次yeild的返回值处理的
function* generator() {
let x1 = yield 10;
console.log(x1);
let x2 = yield 20;
console.log(x2);
return 30;
}
let itor = generator();
itor.next('@1');
itor.next('@2');
itor.next('@3');
// yeild* 后面跟着一个新的itor,后期执行到这的时候,会进入到新的generator中执行
function* generator1() {
yield 10;
yield 20;
}
function* generator2() {
yield 10;
yield* generator1();
yield 20;
}
let itor = generator2();
console.log(itor.next()); //value:10 done:false
console.log(itor.next()); //value:10 done:false
console.log(itor.next()); //value:20 done:false
console.log(itor.next()); //value:20 done:false
console.log(itor.next()); //value:undefined done:true