JavaScript 迭代器

Iterator 迭代器

迭代器(Iterator)接口社裆,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問機(jī)制拙绊。任何數(shù)據(jù)結(jié)構(gòu)只要部署 Iterator 接口泳秀,就可以完成遍歷操作(即依次處理該數(shù)據(jù)結(jié)構(gòu)的所有成員)标沪。

1. Iterator 作用

  • 為各種數(shù)據(jù)結(jié)構(gòu)嗜傅,提供一個統(tǒng)一的金句、簡便地訪問接口吕嘀;
  • 使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列违寞;
  • ES6 創(chuàng)造了一種新的遍歷命令 for...of 循環(huán)趁曼,Iterator 接口主要供 for...of 消費(fèi)。

2. Iterator 遍歷

1)創(chuàng)建一個指針對象挡闰,指向當(dāng)前數(shù)據(jù)結(jié)構(gòu)的起始位置;
2)第一次調(diào)用指針對象的 next 方法,將指針指向數(shù)據(jù)結(jié)構(gòu)的第一個成員(包含 value 和 done 兩個屬性的對象);
3)第二次調(diào)用指針對象的 next 方法掰盘,將指針指向數(shù)據(jù)結(jié)構(gòu)的第二個成員;
4)不斷調(diào)用指針對象的 next 方法,直到它指向數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置愧捕。

3. Iterator 接口

interface IteratorYieldResult<TYield> {
  done?: false;
  value: TYield;
}

interface IteratorReturnResult<TReturn> {
  done: true;
  value: TReturn;
}

type IteratorResult<T, TReturn = any> =
  | IteratorYieldResult<T>
  | IteratorReturnResult<TReturn>;

interface Iterator<T, TReturn = any, TNext = undefined> {
  next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
  return?(value?: TReturn): IteratorResult<T, TReturn>;
  throw?(e?: any): IteratorResult<T, TReturn>;
}

interface Iterable<T> {
  [Symbol.iterator](): Iterator<T>;
}

interface IterableIterator<T> extends Iterator<T> {
  [Symbol.iterator](): IterableIterator<T>;
}

4. Iterator 接口實(shí)現(xiàn)

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

const it = makeIterator(["a", "b"]);

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

5. 默認(rèn)的 Iterator 接口

ES6 規(guī)定瘪阁,默認(rèn)的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的 Symbol.iterator 屬性罗洗,或者說,一個數(shù)據(jù)結(jié)構(gòu)只要具有 Symbol.iterator 屬性轩缤,就可以認(rèn)為是“可遍歷的”(iterable)火的。

Symbol.iterator 屬性本身是一個函數(shù)馏鹤,就是當(dāng)前數(shù)據(jù)結(jié)構(gòu)默認(rèn)的遍歷器生成函數(shù)娇哆。執(zhí)行這個函數(shù)碍讨,就會返回一個遍歷器治力。

Symbol.iterator 屬性名是一個表達(dá)式勃黍,返回 Symbol 對象的 iterator 屬性宵统,是一個預(yù)定義好的覆获、類型為 Symbol 的特殊值马澈。

如下弄息,將對象通過 Symbol.iterator 變成一個可遍歷的對象:

const obj = {
  [Symbol.iterator]: function () {
    return {
      next: function () {
        return {
          value: 1,
          done: true,
        };
      },
    };
  },
};

6. 原生可迭代對象

原生具備 Iterator 接口的數(shù)據(jù)結(jié)構(gòu)如下:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函數(shù)的 arguments 對象
  • NodeList 對象

如下痊班,獲取數(shù)組的遍歷器對象:

const arr = ["a", "b", "c"];
const 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 }

關(guān)于對象(Object)未部署 Iterator 接口的原因:

對象的屬性遍歷順序是無法確定的疑枯,需要開發(fā)者手動指定辩块。遍歷器本質(zhì)上是一種線性處理荆永,對于非線性的數(shù)據(jù)接口部署遍歷器接口废亭,就等于部署一種線性轉(zhuǎn)換具钥。另外對象部署遍歷器接口并不是必要的,因?yàn)槿绻渴鹆司偷扔诒划?dāng)作 Map 結(jié)構(gòu)使用骂删,而 ES6 原生提供 Map 的掌动。

7. 遍歷器對象的 return(),throw()

遍歷器對象除了具有 next()方法粗恢,還可以具有 return()方法和 throw()方法。如果你自己寫遍歷器對象生成函數(shù)眷射,那么 next()方法是必須部署的匙赞,return()方法和 throw()方法是否部署是可選的妖碉。

return()方法的使用場合是涌庭,如果 for...of 循環(huán)提前退出(通常是因?yàn)槌鲥e欧宜,或者有 break 語句),就會調(diào)用 return()方法冗茸。
如果一個對象在完成遍歷前席镀,需要清理或釋放資源蚀狰,就可以部署 return()方法愉昆。

function readLinesSync(file) {
  return {
    [Symbol.iterator]() {
      return {
        next() {
          return { done: false };
        },
        return() {
          file.close();
          return { done: true };
        },
      };
    },
  };
}

8. 類數(shù)組對象

字符串麻蹋、DOM NodeList 對象、arguments 對象都實(shí)現(xiàn)了遍歷器接口扮授,所以可用 for...of 進(jìn)行遍歷:

// 字符串
let str = "hello";

for (let s of str) {
  console.log(s); // h e l l o
}

// DOM NodeList對象
let paras = document.querySelectorAll("p");

for (let p of paras) {
  p.classList.add("test");
}

// arguments對象
function printArgs() {
  for (let x of arguments) {
    console.log(x);
  }
}
printArgs("a", "b");
// 'a'
// 'b'

并不是所有類似數(shù)組的對象都具有 Iterator 接口,一個簡便的解決方法刹勃,就是使用 Array.from 方法將其轉(zhuǎn)為數(shù)組。

const arrayLike = { length: 2, 0: "a", 1: "b" };

// 報(bào)錯
for (let x of arrayLike) {
  console.log(x);
}

// 正確
for (let x of Array.from(arrayLike)) {
  console.log(x);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荔仁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子芽死,更是在濱河造成了極大的恐慌,老刑警劉巖关贵,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異揖曾,居然都是意外死亡亥啦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門翔脱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人媒鼓,你說我怎么就攤上這事×ジ猓” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵枚驻,是天一觀的道長。 經(jīng)常有香客問我再登,道長尔邓,這世上最難降的妖魔是什么锉矢? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮沽损,結(jié)果婚禮上灯节,老公的妹妹穿的比我還像新娘绵估。我一直安慰自己炎疆,他們只是感情好国裳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布形入。 她就那樣靜靜地躺著缝左,像睡著了一般亿遂。 火紅的嫁衣襯著肌膚如雪渺杉。 梳的紋絲不亂的頭發(fā)上蛇数,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天少办,我揣著相機(jī)與錄音苞慢,去河邊找鬼英妓。 笑死挽放,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辑畦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼纯出,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了暂筝?” 一聲冷哼從身側(cè)響起箩言,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤焕襟,失蹤者是張志新(化名)和其女友劉穎陨收,沒想到半個月后鸵赖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體务漩,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡它褪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茫打。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片居触。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡包吝,死狀恐怖饼煞,靈堂內(nèi)的尸體忽然破棺而出诗越,到底是詐尸還是另有隱情,我是刑警寧澤嚷狞,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站荣堰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏振坚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一渡八、第九天 我趴在偏房一處隱蔽的房頂上張望啃洋。 院中可真熱鬧,春花似錦宏娄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卖宠。三九已至巍杈,卻和暖如春扛伍,著一層夾襖步出監(jiān)牢的瞬間秉氧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工汁咏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人作媚。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像纸泡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子女揭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353