es6 Iterator筆記

前言

日常開發(fā)經(jīng)常用到的遍歷,es6其中一章單獨討論了Iterator但對其概念很模糊屯阀,因此想深入研究下降狠。


基礎(chǔ)概念

Iterator 的作用有三個:

  1. 為各種數(shù)據(jù)結(jié)構(gòu),提供一個統(tǒng)一的溜畅、簡便的訪問接口捏卓;
  2. 使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列;
  3. ES6 創(chuàng)造了一種新的遍歷命令for...of循環(huán)慈格,Iterator 接口主要供for...of消費怠晴。
Iterator 的遍歷過程是這樣的。
  1. 創(chuàng)建一個指針對象浴捆,指向當(dāng)前數(shù)據(jù)結(jié)構(gòu)的起始位置蒜田。也就是說,遍歷器對象本質(zhì)上选泻,就是一個指針對象冲粤。
  2. 第一次調(diào)用指針對象的next方法,可以將指針指向數(shù)據(jù)結(jié)構(gòu)的第一個成員滔金。
  3. 第二次調(diào)用指針對象的next方法色解,指針就指向數(shù)據(jù)結(jié)構(gòu)的第二個成員。
  4. 不斷調(diào)用指針對象的next方法餐茵,直到它指向數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置科阎。

每一次調(diào)用next方法,都會返回數(shù)據(jù)結(jié)構(gòu)的當(dāng)前成員的信息忿族。具體來說锣笨,就是返回一個包含value和done兩個屬性的對象蝌矛。其中,value屬性是當(dāng)前成員的值错英,done屬性是一個布爾值入撒,表示遍歷是否結(jié)束。

// 模擬next方法返回值的例子
var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}

由于 Iterator 只是把接口規(guī)格加到數(shù)據(jù)結(jié)構(gòu)之上椭岩,所以茅逮,遍歷器與它所遍歷的那個數(shù)據(jù)結(jié)構(gòu),實際上是分開的判哥,完全可以寫出沒有對應(yīng)數(shù)據(jù)結(jié)構(gòu)的遍歷器對象,或者說用遍歷器對象模擬出數(shù)據(jù)結(jié)構(gòu)挺身。


默認 Iterator接口

ES6 規(guī)定章钾,默認的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator屬性热芹,或者說伊脓,一個數(shù)據(jù)結(jié)構(gòu)只要具有Symbol.iterator屬性,就可以認為是“可遍歷的”(iterable)椰棘。
Symbol.iterator是一個當(dāng)前數(shù)據(jù)結(jié)構(gòu)默認的遍歷器生成函數(shù)邪狞,執(zhí)行這個函數(shù)茅撞,就會返回一個遍歷器。這是一個預(yù)定義好的剑令、類型為 Symbol 的特殊值拄查,所以要放在方括號內(nèi)。

const myIterable = {};
myIterable[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};
[...myIterable] // [1, 2, 3]

class Collection {
  *[Symbol.iterator]() {
    let i = 0;
    while(this[i] !== undefined) {
      yield this[i];
      ++i;
    }
  }
}
let myCollection = new Collection();
myCollection[0] = 1;
myCollection[1] = 2;

for(let value of myCollection) {
  console.log(value);
}
// 1
// 2

上述的案例中碍脏。function* (){}為函數(shù)生成器,與普通函數(shù)的區(qū)別是通常中間用yeild作暫停執(zhí)行的標(biāo)記(類似return)役拴,可以通過next方法恢復(fù)執(zhí)行钾埂。
a[mySymbol] = 'Hello!'let a = { [mySymbol]: 'Hello!' }兩種方法都可以把Symbol添加為屬性名。
案例中實際為命名某Symbol屬性指向一個Generator函數(shù)用于遍歷淤击,即添加了遍歷器接口,在觸發(fā)循環(huán)遍歷時會被調(diào)用汞贸。
原生具備 Iterator 接口的數(shù)據(jù)結(jié)構(gòu):Array矢腻、Map多柑、Set竣灌、String、TypedArray及汉、函數(shù)的 arguments 對象屯烦、NodeList 對象驻龟。

Object之所以沒有默認部署 Iterator 接口,是因為對象的哪個屬性先遍歷类溢,哪個屬性后遍歷是不確定的露懒,需要開發(fā)者手動指定龟梦。本質(zhì)上窃躲,遍歷器是一種線性處理,對于任何非線性的數(shù)據(jù)結(jié)構(gòu)蒂窒,部署遍歷器接口躁倒,就等于部署一種線性轉(zhuǎn)換洒琢。不過秧秉,嚴格地說,對象部署遍歷器接口并不是很必要象迎,因為這時對象實際上被當(dāng)作 Map 結(jié)構(gòu)使用,ES5 沒有 Map 結(jié)構(gòu)呛踊,而 ES6 原生提供了砾淌。


調(diào)用 Iterator 接口的場合

上面的案例也涉及到了。

  1. 解構(gòu)賦值
  2. ...擴展運算符
  3. yield*后面跟的是一個可遍歷的結(jié)構(gòu)谭网,它會調(diào)用該結(jié)構(gòu)的遍歷器接口。yield*后面的 Generator 函數(shù)(沒有return語句時)愉择,等同于在 Generator 函數(shù)內(nèi)部锥涕,部署一個for...of循環(huán)。
function* bar() {
  yield 'x';
  yield* foo();
  yield 'y';
}
// 等同于
function* bar() {
  yield 'x';
  yield 'a';
  yield 'b';
  yield 'y';
}
// 等同于
function* bar() {
  yield 'x';
  for (let v of foo()) {
    yield v;
  }
  yield 'y';
}
for (let v of bar()){
  console.log(v);
}
// "x"
// "a"
// "b"
// "y"
  1. 其他場合for...ofArray.from()窿春,Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]]))Promise.all()Promise.race()例如此類的遍歷方法

遍歷器對象的throw和return

遍歷器對象除了具有next方法尺栖,還可以具有return方法和throw方法嫡纠。如果你自己寫遍歷器對象生成函數(shù),那么next方法是必須部署的,return方法和throw方法是否部署是可選的除盏。

// 情況一
for (let line of readLinesSync(fileName)) {
  console.log(line);
  break;
}
// 情況二
for (let line of readLinesSync(fileName)) {
  console.log(line);
  throw new Error();
}

情況一輸出文件的第一行以后叉橱,就會執(zhí)行return方法,關(guān)閉這個文件者蠕;情況二會在執(zhí)行return方法關(guān)閉文件之后窃祝,再拋出錯誤。
Generator 規(guī)格踱侣,return方法必須返回一個對象

// throw()是將yield表達式替換成一個throw語句粪小。
gen.throw(new Error('出錯了')); // Uncaught Error: 出錯了
// 相當(dāng)于將 let result = yield x + y
// 替換成 let result = throw(new Error('出錯了'));

// return()是將yield表達式替換成一個return語句。
gen.return(2); // Object {value: 2, done: true}
// 相當(dāng)于將 let result = yield x + y
// 替換成 let result = return 2;

因此上述行為符合抡句,先執(zhí)行內(nèi)部探膊,再中斷返回或拋出錯誤


心得總結(jié)

Iterator,其涉及到了Symbol和Generator的知識點待榔。從最基本的原生可遍歷對象開始入手逞壁,難點就在于理解函數(shù)生成器如何運作以及其與Iterator 接口關(guān)聯(lián)起來。
說實話現(xiàn)在日常業(yè)務(wù)開發(fā)很少涉及到去添加或重寫Iterator 接口锐锣。但是一些組件工具方法中腌闯,這是可以利用的“騷操作”??。


參考

阮一峰的ES6--Iterator 和 for...of 循環(huán)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刺下,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子稽荧,更是在濱河造成了極大的恐慌橘茉,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姨丈,死亡現(xiàn)場離奇詭異畅卓,居然都是意外死亡,警方通過查閱死者的電腦和手機蟋恬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門翁潘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人歼争,你說我怎么就攤上這事拜马。” “怎么了沐绒?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵俩莽,是天一觀的道長。 經(jīng)常有香客問我乔遮,道長扮超,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮出刷,結(jié)果婚禮上璧疗,老公的妹妹穿的比我還像新娘。我一直安慰自己馁龟,他們只是感情好崩侠,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屁柏,像睡著了一般啦膜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淌喻,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天僧家,我揣著相機與錄音,去河邊找鬼裸删。 笑死八拱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的涯塔。 我是一名探鬼主播肌稻,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼匕荸!你這毒婦竟也來了爹谭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤榛搔,失蹤者是張志新(化名)和其女友劉穎诺凡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體践惑,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡腹泌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了尔觉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凉袱。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖侦铜,靈堂內(nèi)的尸體忽然破棺而出专甩,到底是詐尸還是另有隱情,我是刑警寧澤钉稍,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布配深,位于F島的核電站,受9級特大地震影響嫁盲,放射性物質(zhì)發(fā)生泄漏篓叶。R本人自食惡果不足惜烈掠,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缸托。 院中可真熱鬧左敌,春花似錦、人聲如沸俐镐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽佩抹。三九已至叼风,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棍苹,已是汗流浹背无宿。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留枢里,地道東北人孽鸡。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像栏豺,于是被迫代替她去往敵國和親彬碱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Iterator(遍歷器)的概念 JavaScript原有的表示“集合”的數(shù)據(jù)結(jié)構(gòu)奥洼,主要是數(shù)組(Array)和對象...
    呼呼哥閱讀 4,449評論 0 2
  • Iterator(遍歷器)的概念 JavaScript原有的表示“集合”的數(shù)據(jù)結(jié)構(gòu)巷疼,主要是數(shù)組和對象,ES6又添加...
    oWSQo閱讀 614評論 0 1
  • 一灵奖、Iterator(遍歷器)的概念 Iterator 是一種接口嚼沿,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問機制。 任何...
    magic_pill閱讀 314評論 0 1
  • 現(xiàn)在大家手機或者電腦上的音樂文件一般都有上百首以上忿檩,如果想轉(zhuǎn)換這些音樂文件的格式是有些麻煩尉尾,不過也能夠批量轉(zhuǎn)換,迅...
    科技的力量閱讀 500評論 0 0
  • 干枯的樹枝開出了花 地上的雨水下回了天 河水滾燙如墨倒著流 世界像是被施了魔咒 沒有人理會夢的盡頭 布谷鳥指引著路...
    白里格閱讀 260評論 0 0