Iterator
任何數(shù)據(jù)結(jié)構(gòu)只要部署 Iterator 接口,就可以完成遍歷操作(即依次處理該數(shù)據(jù)結(jié)構(gòu)的所有成員)。
Iterator 的作用有三個(gè):
- 為各種數(shù)據(jù)結(jié)構(gòu),提供一個(gè)統(tǒng)一的、簡(jiǎn)便的訪問(wèn)接口for...of
- 使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列;
- ES6 創(chuàng)造了一種新的遍歷命令for...of循環(huán),Iterator 接口主要供for...of消費(fèi)。
ES6 規(guī)定,默認(rèn)的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator屬性,或者說(shuō),一個(gè)數(shù)據(jù)結(jié)構(gòu)只要具有Symbol.iterator屬性,就可以認(rèn)為是“可遍歷的”(iterable)
Iterator 接口的目的,就是為所有數(shù)據(jù)結(jié)構(gòu),提供了一種統(tǒng)一的訪問(wèn)機(jī)制,即for...of循環(huán)
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 }
生成一個(gè)Iterater
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++]} :
{done: true};
}
};
}
對(duì)于普通的對(duì)象object,for...of結(jié)構(gòu)不能直接使用,會(huì)報(bào)錯(cuò),必須部署了 Iterator 接口后才能使用,主要因?yàn)閛bject是沒(méi)有順序的。如果想遍歷的話(huà),Object.keys方法將對(duì)象的鍵名生成一個(gè)數(shù)組,然后遍歷這個(gè)數(shù)組
for...of、for...in、forEach的區(qū)別
- for...of
1. 不能遍歷對(duì)象
2. 數(shù)據(jù)結(jié)構(gòu)只要部署了Symbol.iterator屬性,就被視為具有 iterator 接口,就可以用for...of循環(huán)遍歷它的成員
3. for...of循環(huán)可以使用的范圍包括數(shù)組、Set 和 Map 結(jié)構(gòu)、某些類(lèi)似數(shù)組的對(duì)象(比如arguments對(duì)象、DOM NodeList 對(duì)象)、后文的 Generator 對(duì)象,以及字符串
遍歷鍵值鍵名的方式
let arr = ['a', 'b', 'c'];
for (let pair of arr.entries()) {
console.log(pair);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']
- for...in
1. 數(shù)組的鍵名是數(shù)字,但是for...in循環(huán)是以字符串作為鍵名“0”、“1”、“2”等等。
2. for...in循環(huán)不僅遍歷數(shù)字鍵名,還會(huì)遍歷手動(dòng)添加的其他鍵,甚至包括原型鏈上的鍵。
3. for...in循環(huán)會(huì)以任意順序遍歷鍵名,適合遍歷對(duì)象,不適合遍歷數(shù)組
- forEach
1. 無(wú)法中途跳出forEach循環(huán),break命令或return命令都不能奏效
Generater
- Generator 函數(shù)是 ES6 提供的一種異步編程解決方案
Generator 函數(shù)返回的遍歷器對(duì)象,只有調(diào)用next方法才會(huì)遍歷下一個(gè)內(nèi)部狀態(tài),所以其實(shí)提供了一種可以暫停執(zhí)行的函數(shù)。yield表達(dá)式就是暫停標(biāo)志。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();// 返回一個(gè)遍歷器對(duì)象 (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 表達(dá)式
每次遇到y(tǒng)ield,函數(shù)暫停執(zhí)行,下一次再?gòu)脑撐恢美^續(xù)向后執(zhí)行(異步可中斷,與react的機(jī)制相同,但是會(huì)引進(jìn)新的副作用,所以沒(méi)被react采用)。
- 與 Iterator 接口的關(guān)系
Generator 函數(shù)執(zhí)行后,返回一個(gè)遍歷器對(duì)象。該對(duì)象本身也具有Symbol.iterator屬性,執(zhí)行后返回自身。
function* gen(){
// some code
}
var g = gen();
g[Symbol.iterator]() === g
// true
Generater的異步應(yīng)用
- 異步編程的方法
- 回調(diào)函數(shù)
- 事件監(jiān)聽(tīng)
- 發(fā)布/訂閱
- Promise 對(duì)象
- Generater
- async...await
- 協(xié)程
意思是多個(gè)線(xiàn)程互相協(xié)作,完成異步任務(wù)
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 函數(shù)
任何函數(shù),只要參數(shù)有回調(diào)函數(shù),就能寫(xiě)成 Thunk 函數(shù)的形式
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 函數(shù)的 Generator 執(zhí)行器
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模塊自動(dòng)執(zhí)行
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);