Iterator
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:
- 为各种数据结构,提供一个统一的、简便的访问接口for...of
- 使得数据结构的成员能够按某种次序排列;
- ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)
Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环
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 }
生成一个Iterater
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++]} :
{done: true};
}
};
}
对于普通的对象object,for...of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用,主要因为object是没有顺序的。如果想遍历的话,Object.keys方法将对象的键名生成一个数组,然后遍历这个数组
for...of、for...in、forEach的区别
- for...of
1. 不能遍历对象
2. 数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for...of循环遍历它的成员
3. for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串
遍历键值键名的方式
let arr = ['a', 'b', 'c'];
for (let pair of arr.entries()) {
console.log(pair);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']
- for...in
1. 数组的键名是数字,但是for...in循环是以字符串作为键名“0”、“1”、“2”等等。
2. for...in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
3. for...in循环会以任意顺序遍历键名,适合遍历对象,不适合遍历数组
- forEach
1. 无法中途跳出forEach循环,break命令或return命令都不能奏效
Generater
- Generator 函数是 ES6 提供的一种异步编程解决方案
Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();// 返回一个遍历器对象 (Iterator Object)
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
- yield 表达式
每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行(异步可中断,与react的机制相同,但是会引进新的副作用,所以没被react采用)。
- 与 Iterator 接口的关系
Generator 函数执行后,返回一个遍历器对象。该对象本身也具有Symbol.iterator属性,执行后返回自身。
function* gen(){
// some code
}
var g = gen();
g[Symbol.iterator]() === g
// true
Generater的异步应用
- 异步编程的方法
- 回调函数
- 事件监听
- 发布/订阅
- Promise 对象
- Generater
- async...await
- 协程
意思是多个线程互相协作,完成异步任务
var fetch = require('node-fetch');
function* gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
var g = gen();
var result = g.next();
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data);
});
- Thunk 函数
任何函数,只要参数有回调函数,就能写成 Thunk 函数的形式
const Thunk = function(fn) {
return function (...args) {
return function (callback) {
return fn.call(this, ...args, callback);
}
};
};
var readFileThunk = Thunk(fs.readFile);
readFileThunk(fileA)(callback);
基于 Thunk 函数的 Generator 执行器
function run(fn) {
var gen = fn();
function next(err, data) {
var result = gen.next(data);
if (result.done) return;
result.value(next);
}
next();
}
function* g() {
// ...
}
run(g);
CO模块自动执行
function run(gen){
var g = gen();
function next(data){
var result = g.next(data);
if (result.done) return result.value;
result.value.then(function(data){
next(data);
});
}
next();
}
run(gen);