Iterator迭代器
ES6新增的内容
let/const/class、ES6Module模块规范(import export)、Symbol/BigInt、箭头函数、解构赋值、...、数组和对象以及正则新增了一些方法、模板字符串、Set/Map...
Promise、Proxy、Reflect、Iterator、Generator...
Iterator迭代器
只是一种机制,可以为各种不同的数据结构提供统一的循环和迭代规范,而for of循环本身就是基于这种进制进行迭代的!
- 拥有 Iterator 机制的对象,必须具备 next 方法:执行这个方法可以依次访问对象中的每个成员
- 执行next返回值是一个对象:
- value:当前迭代的这一项
- done:记录是否迭代完成
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 { value: undefined, done: true }; } return { value: assemble[self.index++], done: false }; } } 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}虽然不具备 Iterator 内置类,但是对于某些数据结构,它提供了 Symbol.iterator 属性方法,这个方法具备迭代器规范,基于这个方法可以依次迭代数据中的每一项
- 数组 Array.prototype[Symbol.iterator]=function...
- Set.prototype / Map.prototype
- String.prototype
- NodeList.prototype
- arguments[Symbol.iterator]
- generator object
- ...
把Symbol.iterator方法执行,会返回一个具备迭代器规范的itor对象,基于itor.next()依次执行,就可以获取到数据集合中的每一项!!
let arr = [10, 20, 30]; let itor = arr[Symbol.iterator](); 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:undefined,done:true}ES6中新提供的“for...of”循环,就是按照这套机制去迭代的!!
1.先去找 arr[Symbol.iterator] 执行(如果数据集合不具备这个属性,就会报错「Uncaught TypeError: xxx is not iterable」),返回一个迭代器对象 itor
2.每一轮循环都会执行一次 itor.next() 方法,把结果中的value赋值给循环中的value;当done为true时,则结束整个循环!!
let arr = [10, 20, 30]; arr[Symbol.iterator] = function () { let self = this, index = 0; return { next() { if (index > self.length - 1) { return { value: undefined, done: true }; } let result = { value: self[index], done: false }; index += 2; return result; } }; }; for (let value of arr) { console.log(value); }Object.prototype上不具备Symbol.iterator,一个普通对象默认不能基于迭代器规范循环,也就是不能使用for/of;但是可通过在原型上添加Symbol.iterator来实现迭代器规范
Object.prototype[Symbol.iterator] = function () { let self = this, keys = Reflect.ownKeys(self), index = 0; return { next() { if (index >= keys.length) { return { value: undefined, done: true }; } return { value: self[keys[index++]], done: false }; } }; }; let obj = { name: 'zhufeng', age: 13, lx: 0 }; for (let value of obj) { console.log(value); }类数组可直接使用Array.prototype[Symbol.iterator],不需再进行重写
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); }
JS中常用的循环
- for循环、while循环、Array.prototype.forEach可以迭代数组
- for of循环 「扩充:for await of」
- for in循环 [for in循环是无法迭代symbol类型的私有属性]
性能从高到低:
for循环(i是私有的) -> for循环(i是全局的) && while循环」-> forEach循环(内部封装的方法,肯定做了一些逻辑判断处理,所以要稍微比命令式编程慢一些) -> for/of循环 -> for/in循环(它会依次查找私有和原型链上所有可枚举的属性,所以比其他循环慢很多,项目中不建议使用for/in)
console.time('FOR'); for (var i = 0; i < arr.length; i++) { } console.timeEnd('FOR'); console.time('FOR2'); let m = 0; for (; m < arr.length; m++) { } console.timeEnd('FOR2'); console.time('WHILE'); let k = 0; while (k < arr.length) { k++; } console.timeEnd('WHILE'); console.time('FOREACH'); arr.forEach(() => { }); console.timeEnd('FOREACH'); console.time('FOROF'); for (let value of arr) { } console.timeEnd('FOROF'); console.time('FORIN'); for (let key in arr) { } console.timeEnd('FORIN');密集数组 [10,20,30,40]
稀疏数组 {1:20,2:30,length:6}
forEach迭代的时候 对于稀疏数组,只迭代有内容的,例如:第二个数组只迭代两次
Generator和Await原理
Generator生成器函数 function* 函数名(){}
fn(10,20)
- 函数体中的代码并没有执行「实参值已经预先传递进去了」
- 返回一个具备迭代器规范的对象itor:next/return/throw
itor -> fn.prototype -> GeneratorFunction.prototype(next/return/throw) -> 原型对象(Symbol.iterator) -> Object.prototype
执行itor.next()才会执行函数体中的代码
- 把之前预先传递的实参赋值给形参变量
- this->window
- 遇到 yeild 或者 return 结束
- 返回的结果是一个对象 {value:yeild或者return后的值,done:false/true}
function* fn(x, y) { console.log(x, y); console.log(this); return 10; } fn.prototype.x = 100; let itor = fn(10, 20); console.log(itor.next()); //{value:10,done:true}function* generator() { console.log('A'); yield 10; console.log('B'); yield 20; console.log('D'); return 100; } let itor = generator(); console.log(itor.next()); //输出A {value:10,done:false} console.log(itor.next()); //输出B {value:20,done:false} console.log(itor.next()); //输出D {value:100,done:true} console.log(itor.next()); // {value:undefined,done:true}next/throw/return
function* generator() { yield 10; yield 20; yield 30; } let itor = generator(); console.log(itor.next()); //{value:10,done:false} // console.log(itor.throw('异常原因')); //手动抛出异常,结束函数中的代码执行 // console.log(itor.return(100)); //{value:100,done:true} 遇到return则结束函数执行,done设置为true console.log(itor.next()); //{value:undefined,done:true}next传值
function* generator() { let res = yield 10; console.log(res); res = yield 20; console.log(res); res = yield 30; console.log(res); } let itor = generator(); console.log(itor.next(100)); //{value:10,done:false} 第一次执行next传递的值没有用 console.log(itor.next(200)); //把200赋值给第一个res 200 {value:20,done:false} 每一次next传递的值,会做为上一次yeild执行的返回结果 console.log(itor.next(300)); //把300赋值给第二个res 300 {value:30,done:false} console.log(itor.next(400)); //把400赋值给第三个res 400 {value:undefined,done:true}yield 后面为 Generator生成器函数
function* generator1() { yield 10; yield 20; } function* generator2() { yield 30; yield* generator1(); //yeild* 可以保证代码执行到这的时候,进入到新的generator函数中去执行 yield 40; } let itor = generator2(); console.log(itor.next()); //value:30 done:false console.log(itor.next()); //value:10 done:false console.log(itor.next()); //value:20 done:false console.log(itor.next()); //value:40 done:false console.log(itor.next()); //value:undefined done:true
需求:串行发送三个请求,请求时间分别是 1000/2000/3000
const query = interval => { return new Promise(resolve => { setTimeout(() => { resolve(interval); }, interval); }); }; query(1000).then(value => { console.log('第一个成功:', value); return query(2000); }).then(value => { console.log('第二个成功:', value); return query(3000); }).then(value => { console.log('第三个成功:', value); });function* generator() { let value = yield query(1000); console.log('第一个成功:', value); value = yield Promise.reject('xxx'); console.log('第二个成功:', value); value = yield query(3000); console.log('第三个成功:', value); }) let itor = generator(); // itor.next(); //value:第一次请求的promise实例,接下来我们需要等待本次请求成功,获取到结果后,在去执行下一次的next方法 itor.next().value.then(val => { // val:第一次请求成功的结果 itor.next(val).value.then(val => { // val:第二次请求成功的结果 itor.next(val).value.then(val => { // val:第三次请求成功的结果 itor.next(val); }); }); });const isPromise = function isPromise(x) { if (x !== null && /^(object|function)$/i.test(typeof x)) { var then; try { then = x.then; } catch (_) { return false; } if (typeof then === "function") return true; } return false; }; // co.js function AsyncFunction(generator, ...params) { return new Promise((resolve, reject) => { let itor = generator(...params); const next = val => { let { value, done } = itor.next(val); if (done) { resolve(value); return; } if (!isPromise(value)) value = Promise.resolve(value); value.then(val => next(val)) .catch(reason => { reject(reason); itor.throw(reason); }); }; next(); }); } AsyncFunction(function* () { let value = yield query(1000); console.log('第一个成功:', value); value = yield Promise.reject('xxx'); console.log('第二个成功:', value); value = yield query(3000); console.log('第三个成功:', value); }).then(value => { console.log('请求都成功:', value); }).catch(reason => { console.log('某次请求失败:', reason); });// async await 是 generator+promise 的“语法糖” (async () => { let result = await query(1000); console.log(`第一个请求成功,结果是:${result}`); result = await query(2000); console.log(`第二个请求成功,结果是:${result}`); result = await query(3000); console.log(`第三个请求成功,结果是:${result}`); })();