爱是天时地利的迷信---《原来你也在这里》
宝宝们,周末过得充实有趣吗?今天上午下雨了,时小时大,雨声很好听~
speak is cheap ~
一、Iterator
Iterator(遍历器)的概念
JS里原有的表示”集合“的数据结构,主要是Array和Object,ES6又添加了Map和Set。我们可以任意组合和设计数据的结构,那么就需要一个机制,可处理所有不同的数据结构。
Iterator就是这个用途,他是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据只要不输Iterator接口,就可以完成遍历操作(依次处理该数据结构的所有成员)。
Iterator作用
Iterator的遍历过程
每次调用next方法, 都会返回数据结构的当前成员的信息。返回一个包含value和done两个属性的对象。其中,value是当前成员的值,done是一个表示遍历是否结束的布尔值,即表示是否有必要在一次调用next方法。
Iterator
Iterator接口的目的,就是为所有数据结构提供一种统一的访问机制。即for...of循环。当使用for...of循环遍历某种数据结构时,该循环会自动寻找Iterator接口。
数据结构只要部署了Iterator接口,我们就称这种数据结构是”可遍历的“
ES6规定,默认的Iterator接口部署在数据结构的Symbol.iterator属性,Symbol.iterator属性本身是一个函数,是当前数据结构默认的遍历器生成函数。执行这个函数就返回一个遍历器。
上面的话头大吗?还是看代码吧!
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
ES6的某些数据结构原生部署了Symbol.iteraotr属性,即不用任何处理就可以被for...of循环遍历。另外一些数据结构没有。
原生具备Iterator接口的数据结构:
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
调用Iterator接口的场合
有些场合会默认调用Iterator接口,如下:
1.解构赋值
对数组和Set结构解构赋值
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];
2.扩展运算符
扩展用算符(...)也会调用默认的Iterator接口
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
3.yield*
yield*后面跟的是一个可遍历的结构,他会调用该结构的遍历器接口
let generator = function* () {
yield 1;
yield* [2,3,4];
yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }
4.其他场合
任何接受数组最为参数的场合,其实都调用了遍历器接口:
Iterator 接口最简单的实现
Symbol.iterator方法最简单实现,还是使用下一章介绍的Generator函数
let myIterable ={
[Symbol.iterator]:function*(){
yield 1;
yield 2;
yield 3;
}
}
[...myIterable] //[1,2,3]
//更简洁写法
let obj = {
*[Symbol.iterator](){
yield 'hello';
yield 'world';
}
}
for(let x of obj){
console.log(x)
}
// 'hello'
// 'world'
与其他遍历语法的比较
二、Generotor
Generator的概念
Generator函数是ES6提供的一种异步编程解决方案,语法行为和传统函数完全不同。
在语法上,Generator函数是一个状态机,封装了多个内部状态。
执行Generator函数会返回一个遍历器对象,也就是说,他还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。
形式上,Generator函数是一个普通函数,有两个特征:
function* helloWorldGenerator(){
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
Generator函数调用与普通函数一样,但是,调用Generator函数后,该函数并不执行。返回的也不是函数运行结果,而是一个指向内部状态的指针对象(遍历器对象,Iterator对象);
必须调用遍历器对象的next方法,使得指针移向下一个状态。每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。即,yield是分段执行的,yield表达式是暂停执行的标志,而next方法可以恢复执行。
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
未完待续……
愿我们有能力不向生活缴械投降---Lin