Symbol.iterator 遍歷器接口

Iterator(遍歷器)的概念
JavaScript 原有的表示“集合”的數(shù)據(jù)結(jié)構(gòu),主要是數(shù)組(Array)和對(duì)象(Object),ES6 又添加了Map和Set。
[[1, 2],{a: 1, b: 2},new Set([1, 2]),new Map([['a',1],['b',2]])]
這樣就有了四種數(shù)據(jù)集合,用戶還可以組合使用它們,定義自己的數(shù)據(jù)結(jié)構(gòu),比如數(shù)組的成員是Map,Map的成員是對(duì)象。這樣就需要一種統(tǒng)一的接口機(jī)制,來(lái)處理所有不同的數(shù)據(jù)結(jié)構(gòu)。
遍歷器(Iterator)就是這樣一種機(jī)制。它是一種接口,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問(wèn)機(jī)制。任何數(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)接口;二是使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列;三是 ES6 創(chuàng)造了一種新的遍歷命令for...of循環(huán),Iterator 接口主要供 for...of 消費(fèi)。
當(dāng)使用 for...of 循環(huán)遍歷某種數(shù)據(jù)結(jié)構(gòu)時(shí),該循環(huán)會(huì)自動(dòng)去尋找 Iterator 接口。
ES6 規(guī)定,默認(rèn)的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的 Symbol.iterator 屬性,或者說(shuō),一個(gè)數(shù)據(jù)結(jié)構(gòu)只要具有 Symbol.iterator 屬性,就可以認(rèn)為是“可遍歷的”。
一個(gè)對(duì)象如果要具備可被 for...of 循環(huán)調(diào)用的 Iterator 接口,就必須在Symbol.iterator的屬性上部署遍歷器生成方法。
let obj = {0: 1,1: 2,2: 3,length: 3,[Symbol.iterator] () {let that = this;let len = 0;return {next () {return {done: len === that.length, value: that[len++]}}}}}for (const i of obj) {console.log(i)}
有了遍歷器接口,數(shù)據(jù)結(jié)構(gòu)就可以用 for...of 循環(huán)遍歷,也可以使用 while 循環(huán)遍歷。遍歷器對(duì)象每次移動(dòng)指針(next方法),都檢查一下返回值的 done 屬性,如果遍歷還沒(méi)結(jié)束,就移動(dòng)遍歷器對(duì)象的指針到下一步(next方法),不斷循環(huán)。
原生具備 Iterator 接口的數(shù)據(jù)結(jié)構(gòu)如下。
ArrayMapSetStringTypedArray函數(shù)的 arguments 對(duì)象NodeList 對(duì)象
下面的例子是數(shù)組的 Symbol.iterator 屬性。
let arr = ['a', 'b', 'c'];let iter = arr[Symbol.iterator](); // 遍歷器對(duì)象(即指針對(duì)象)iter.next() // { value: 'a', done: false } // 指針對(duì)象的next方法,用來(lái)移動(dòng)指針。iter.next() // { value: 'b', done: false } // 這個(gè)對(duì)象具有value和done兩個(gè)屬性iter.next() // { value: 'c', done: false }iter.next() // { value: undefined, done: true }
調(diào)用 Generator 函數(shù)后,該函數(shù)并不執(zhí)行,返回的也不是函數(shù)運(yùn)行結(jié)果,而是一個(gè)指向內(nèi)部狀態(tài)的指針對(duì)象,也就是上面介紹的遍歷器對(duì)象(Iterator Object)。
let obj = {0: 1,1: 2,2: 3,length: 3,[Symbol.iterator]: function * gen () {let len = 0while (len < this.length) {yield this[len++]}}}for (const i of obj) {console.log(i)}
總結(jié):
遍歷器它是一種接口,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問(wèn)機(jī)制。
Symbol.iterator 屬性的數(shù)據(jù)結(jié)構(gòu),就稱(chēng)為部署了遍歷器接口。調(diào)用這個(gè)接口,就會(huì)返回一個(gè)遍歷器對(duì)象。
遍歷器對(duì)象上每次調(diào)用 next 方法,都會(huì)返回一個(gè)代表當(dāng)前成員的信息對(duì)象,具有 value 和 done 兩個(gè)屬性。
調(diào)用 Generator 函數(shù)后,返回的也不是函數(shù)運(yùn)行結(jié)果,而是一個(gè)指向內(nèi)部狀態(tài)的指針對(duì)象,也就是遍歷器對(duì)象。
