一文帶你理解:可以迭代大部分?jǐn)?shù)據(jù)類型的 for…of 為什么不能遍歷普通對(duì)象?

for…of 及其使用

??我們知道力试,ES6 中引入 for...of 循環(huán)贮预,很多時(shí)候用以替代 for...inforEach() 贝室,并支持新的迭代協(xié)議。for...of 允許你遍歷 Array(數(shù)組), String(字符串), Map(映射), Set(集合),TypedArray(類型化數(shù)組)仿吞、arguments档玻、NodeList對(duì)象、Generator等可迭代的數(shù)據(jù)結(jié)構(gòu)等茫藏。for...of語(yǔ)句在可迭代對(duì)象上創(chuàng)建一個(gè)迭代循環(huán)误趴,調(diào)用自定義迭代鉤子,并為每個(gè)不同屬性的執(zhí)行語(yǔ)句务傲。

for...of的語(yǔ)法:

for (variable of iterable) {
    // statement
}
// variable:每個(gè)迭代的屬性值被分配給該變量凉当。
// iterable:一個(gè)具有可枚舉屬性并且可以迭代的對(duì)象。

常用用法

{
  // 迭代字符串
  const iterable = 'ES6';
  for (const value of iterable) {
    console.log(value);
  }
  // Output:
  // "E"
  // "S"
  // "6"
}
{
  // 迭代數(shù)組
  const iterable = ['a', 'b'];
  for (const value of iterable) {
    console.log(value);
  }
  // Output:
  // a
  // b
}
{
  // 迭代Set(集合)
  const iterable = new Set([1, 2, 2, 1]);
  for (const value of iterable) {
    console.log(value);
  }
  // Output:
  // 1
  // 2
}
{
  // 迭代Map
  const iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);
  for (const entry of iterable) {
    console.log(entry);
  }
  // Output:
  // ["a", 1]
  // ["b", 2]
  // ["c", 3]

  for (const [key, value] of iterable) {
    console.log(value);
  }
  // Output:
  // 1
  // 2
  // 3
}
{
  // 迭代Arguments Object(參數(shù)對(duì)象)
  function args() {
    for (const arg of arguments) {
      console.log(arg);
    }
  }
  args('a', 'b');
  // Output:
  // a
  // b
}
{
  // 迭代生成器
  function* foo(){ 
    yield 1; 
    yield 2; 
    yield 3; 
  }; 

  for (let o of foo()) { 
    console.log(o); 
  }
  // Output:
  // 1
  // 2
  // 3
}

Uncaught TypeError: obj is not iterable

// 普通對(duì)象
const obj = {
  foo: 'value1',
  bar: 'value2'
}
for(const item of obj){
  console.log(item)
}
// Uncaught TypeError: obj is not iterable

??可以看出售葡,for of可以迭代大部分對(duì)象甚至字符串看杭,卻不能遍歷普通對(duì)象。

如何用for...of迭代普通對(duì)象

??通過(guò)前面的基本用法挟伙,我們知道楼雹,for...of可以迭代數(shù)組、Map等數(shù)據(jù)結(jié)構(gòu)尖阔,順著這個(gè)思路贮缅,我們可以結(jié)合對(duì)象的Object.values()Object.keys()介却、Object.entries()方法以及解構(gòu)賦值的知識(shí)來(lái)用for...of遍歷普通對(duì)象谴供。

  • Object.values()Object.keys()齿坷、Object.entries()用法及返回值
const obj = {
  foo: 'value1',
  bar: 'value2'
}
// 打印由value組成的數(shù)組
console.log(Object.values(obj)) // ["value1", "value2"]

// 打印由key組成的數(shù)組
console.log(Object.keys(obj)) // ["foo", "bar"]

// 打印由[key, value]組成的二維數(shù)組
// copy(Object.entries(obj))可以把輸出結(jié)果直接拷貝到剪貼板桂肌,然后黏貼
console.log(Object.entries(obj)) // [["foo","value1"],["bar","value2"]]
  • 因?yàn)?code>for...of可以迭代數(shù)組和Map数焊,所以我們得到以下遍歷普通對(duì)象的方法
const obj = {
  foo: 'value1',
  bar: 'value2'
}
// 方法一:使用for of迭代Object.entries(obj)形成的二維數(shù)組,利用解構(gòu)賦值得到value
for(const [, value] of Object.entries(obj)){
  console.log(value) // value1, value2
}

// 方法二:Map
// 普通對(duì)象轉(zhuǎn)Map
// Map 可以接受一個(gè)數(shù)組作為參數(shù)崎场。該數(shù)組的成員是一個(gè)個(gè)表示鍵值對(duì)的數(shù)組
console.log(new Map(Object.entries(obj)))

// 遍歷普通對(duì)象生成的Map
for(const [, value] of new Map(Object.entries(obj))){
  console.log(value) // value1, value2
}

// 方法三:繼續(xù)使用for in
for(const key in obj){
  console.log(obj[key]) // value1, value2
}

{
  // 方法四:將【類數(shù)組(array-like)對(duì)象】轉(zhuǎn)換為數(shù)組
  // 該對(duì)象需具有一個(gè) length 屬性佩耳,且其元素必須可以被索引。
  const obj = {
    length: 3, // length是必須的谭跨,否則什么也不會(huì)打印
    0: 'foo',
    1: 'bar',
    2: 'baz',
    a: 12  // 非數(shù)字屬性是不會(huì)打印的
  };
  const array = Array.from(obj); // ["foo", "bar", "baz"]
  for (const value of array) { 
      console.log(value);
  }
  // Output: foo bar baz
}
{
  // 方法五:給【類數(shù)組】部署數(shù)組的[Symbol.iterator]方法【對(duì)普通字符串屬性對(duì)象無(wú)效】
  const iterable = {
    0: 'a',
    1: 'b',
    2: 'c',
    length: 3,
    [Symbol.iterator]: Array.prototype[Symbol.iterator]
  };
  for (let item of iterable) {
    console.log(item); // 'a', 'b', 'c'
  }
}

注意事項(xiàng)

  • 有別于不可終止遍歷的forEach干厚,for...of的循環(huán)可由breakthrow饺蚊, continuereturn終止,在這些情況下悬嗓,迭代器關(guān)閉污呼。
  const obj = {
    foo: 'value1',
    bar: 'value2',
    baz: 'value3'
  }
  for(const [, value] of Object.entries(obj)){
    if (value === 'value2') break // 不會(huì)再執(zhí)行下次迭代
    console.log(value) // value1
  };
  [1,2].forEach(item => {
      if(item == 1) break // Uncaught SyntaxError: Illegal break statement
      console.log(item)
  });
  [1,2].forEach(item => {
      if(item == 1) continue // Uncaught SyntaxError: Illegal continue statement: no surrounding iteration statement
      console.log(item)
  });
  [1,2].forEach(item => {
      if(item == 1) return // 仍然會(huì)繼續(xù)執(zhí)行下一次循環(huán),打印2
      console.log(item) // 2
  })
  • For…ofFor…in對(duì)比

    • for...in 不僅枚舉數(shù)組聲明包竹,它還從構(gòu)造函數(shù)的原型中查找繼承的非枚舉屬性燕酷;
    • for...of 不考慮構(gòu)造函數(shù)原型上的不可枚舉屬性(或者說(shuō)for...of語(yǔ)句遍歷可迭代對(duì)象定義要迭代的數(shù)據(jù)。)周瞎;
    • for...of 更多用于特定的集合(如數(shù)組等對(duì)象)苗缩,但不是所有對(duì)象都可被for...of迭代声诸。
      Array.prototype.newArr = () => {};
      Array.prototype.anotherNewArr = () => {};
      const array = ['foo', 'bar', 'baz'];
      for (const value in array) { 
        console.log(value); // 0 1 2 newArr anotherNewArr
      }
      for (const value of array) { 
        console.log(value); // 'foo', 'bar', 'baz'
      }
    

普通對(duì)象為何不能被 for of 迭代

??前面我們有提到一個(gè)詞叫“可迭代”數(shù)據(jù)結(jié)構(gòu)慰照,當(dāng)用for of迭代普通對(duì)象時(shí),也會(huì)報(bào)一個(gè)“not iterable”的錯(cuò)誤。實(shí)際上,任何具有 Symbol.iterator 屬性的元素都是可迭代的齐鲤。我們可以簡(jiǎn)單查看幾個(gè)可被for of迭代的對(duì)象捧灰,看看和普通對(duì)象有何不同:

[圖片上傳失敗...(image-869405-1607263974085)]

[圖片上傳失敗...(image-86da24-1607263974085)]

[圖片上傳失敗...(image-9dd87f-1607263974085)]

??可以看到煌寇,這些可被for of迭代的對(duì)象,都實(shí)現(xiàn)了一個(gè)Symbol(Symbol.iterator)方法,而普通對(duì)象沒有這個(gè)方法更振。

??簡(jiǎn)單來(lái)說(shuō)乎芳,for of 語(yǔ)句創(chuàng)建一個(gè)循環(huán)來(lái)迭代可迭代的對(duì)象吭净,可迭代的對(duì)象內(nèi)部實(shí)現(xiàn)了Symbol.iterator方法,而普通對(duì)象沒有實(shí)現(xiàn)這一方法肴甸,所以普通對(duì)象是不可迭代的寂殉。

Iterator(遍歷器)

??關(guān)于Iterator(遍歷器)的概念,可以參照阮一峰大大的《ECMAScript 6 入門》——Iterator(遍歷器)的概念

[圖片上傳失敗...(image-a60031-1607263974085)]

??簡(jiǎn)單來(lái)說(shuō)原在,ES6 為了統(tǒng)一集合類型數(shù)據(jù)結(jié)構(gòu)的處理友扰,增加了 iterator 接口彤叉,供 for...of 使用,簡(jiǎn)化了不同結(jié)構(gòu)數(shù)據(jù)的處理村怪。而 iterator 的遍歷過(guò)程秽浇,則是類似 Generator 的方式,迭代時(shí)不斷調(diào)用next方法甚负,返回一個(gè)包含value(值)和done屬性(標(biāo)識(shí)是否遍歷結(jié)束)的對(duì)象柬焕。

如何實(shí)現(xiàn)Symbol.iterator方法,使普通對(duì)象可被 for of 迭代

??依據(jù)上文的指引梭域,我們先看看數(shù)組的Symbol.iterator接口:

const arr = [1,2,3];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: undefined, done: true}

??我們可以嘗試給普通對(duì)象實(shí)現(xiàn)一個(gè)Symbol.iterator接口:

// 普通對(duì)象
const obj = {
  foo: 'value1',
  bar: 'value2',
  [Symbol.iterator]() {
    // 這里Object.keys不會(huì)獲取到Symbol.iterator屬性斑举,原因見下文
    const keys = Object.keys(obj); 
    let index = 0;
    return {
      next: () => {
        if (index < keys.length) {
          // 迭代結(jié)果 未結(jié)束
          return {
            value: this[keys[index++]],
            done: false
          };
        } else {
          // 迭代結(jié)果 結(jié)束
          return { value: undefined, done: true };
        }
      }
    };
  }
}
for (const value of obj) {
  console.log(value); // value1 value2
};

??上面給obj實(shí)現(xiàn)了Symbol.iterator接口,甚至我們還可以像下面這樣:

console.log([...obj]); // ["value1", "value2"]
console.log([...{}]); // console.log is not iterable (cannot read property Symbol(Symbol.iterator))

??我們給obj對(duì)象實(shí)現(xiàn)了一個(gè)Symbol.iterator接口病涨,在此富玷,有一點(diǎn)需要說(shuō)明的是,不用擔(dān)心[Symbol.iterator]屬性會(huì)被Object.keys()獲取到導(dǎo)致遍歷結(jié)果出錯(cuò)没宾,因?yàn)?code>Symbol.iterator這樣的Symbol屬性凌彬,需要通過(guò)Object.getOwnPropertySymbols(obj)才能獲取沸柔,Object.getOwnPropertySymbols() 方法返回一個(gè)給定對(duì)象自身的所有 Symbol 屬性的數(shù)組循衰。

??有一些場(chǎng)合會(huì)默認(rèn)調(diào)用 Iterator 接口(即Symbol.iterator方法:

  • 擴(kuò)展運(yùn)算符...:這提供了一種簡(jiǎn)便機(jī)制,可以將任何部署了 Iterator 接口的數(shù)據(jù)結(jié)構(gòu)褐澎,轉(zhuǎn)為數(shù)組会钝。也就是說(shuō),只要某個(gè)數(shù)據(jù)結(jié)構(gòu)部署了 Iterator 接口工三,就可以對(duì)它使用擴(kuò)展運(yùn)算符迁酸,將其轉(zhuǎn)為數(shù)組(毫不意外的,代碼[...{}]會(huì)報(bào)錯(cuò)俭正,而[...'123']會(huì)輸出數(shù)組['1','2','3'])奸鬓。
  • 數(shù)組和可迭代對(duì)象的解構(gòu)賦值(解構(gòu)是ES6提供的語(yǔ)法糖,其實(shí)內(nèi)在是針對(duì)可迭代對(duì)象Iterator接口掸读,通過(guò)遍歷器按順序獲取對(duì)應(yīng)的值進(jìn)行賦值串远。而普通對(duì)象解構(gòu)賦值的內(nèi)部機(jī)制,是先找到同名屬性儿惫,然后再賦給對(duì)應(yīng)的變量澡罚。);
  • yield*_yield*后面跟的是一個(gè)可遍歷的結(jié)構(gòu)肾请,它會(huì)調(diào)用該結(jié)構(gòu)的遍歷器接口留搔;
  • 由于數(shù)組的遍歷會(huì)調(diào)用遍歷器接口,所以任何接受數(shù)組作為參數(shù)的場(chǎng)合铛铁,其實(shí)都調(diào)用隔显;
  • 字符串是一個(gè)類似數(shù)組的對(duì)象却妨,也原生具有Iterator接口,所以也可被for of迭代荣月。

迭代器模式

??迭代器模式提供了一種方法順序訪問(wèn)一個(gè)聚合對(duì)象中的各個(gè)元素管呵,而又無(wú)需暴露該對(duì)象的內(nèi)部實(shí)現(xiàn),這樣既可以做到不暴露集合的內(nèi)部結(jié)構(gòu)哺窄,又可讓外部代碼透明地訪問(wèn)集合內(nèi)部的數(shù)據(jù)捐下。迭代器模式為遍歷不同的集合結(jié)構(gòu)提供了一個(gè)統(tǒng)一的接口,從而支持同樣的算法在不同的集合結(jié)構(gòu)上進(jìn)行操作萌业。

??不難發(fā)現(xiàn)坷襟,Symbol.iterator實(shí)現(xiàn)的就是一種迭代器模式。集合對(duì)象內(nèi)部實(shí)現(xiàn)了Symbol.iterator接口生年,供外部調(diào)用婴程,而我們無(wú)需過(guò)多的關(guān)注集合對(duì)象內(nèi)部的結(jié)構(gòu),需要處理集合對(duì)象內(nèi)部的數(shù)據(jù)時(shí)抱婉,我們通過(guò)for of調(diào)用Symbol.iterator接口即可档叔。

??比如針對(duì)前文普通對(duì)象的Symbol.iterator接口實(shí)現(xiàn)一節(jié)的代碼,如果我們對(duì)obj里面的數(shù)據(jù)結(jié)構(gòu)進(jìn)行了如下調(diào)整蒸绩,那么衙四,我們只需對(duì)應(yīng)的修改供外部迭代使用的Symbol.iterator接口,即可不影響外部迭代調(diào)用:

const obj = {
  // 數(shù)據(jù)結(jié)構(gòu)調(diào)整
  data: ['value1', 'value2'],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.data.length) {
          // 迭代結(jié)果 未結(jié)束
          return {
            value: this.data[index++],
            done: false
          };
        } else {
          // 迭代結(jié)果 結(jié)束
          return { value: undefined, done: true };
        }
      }
    };
  }
}
// 外部調(diào)用
for (const value of obj) {
  console.log(value); // value1 value2
}

??實(shí)際使用時(shí)患亿,我們可以把上面的Symbol.iterator提出來(lái)進(jìn)行單獨(dú)封裝传蹈,這樣就可以對(duì)一類數(shù)據(jù)結(jié)構(gòu)進(jìn)行迭代操作了。當(dāng)然步藕,下面的代碼只是最簡(jiǎn)單的示例惦界,你可以在此基礎(chǔ)上探究更多實(shí)用的技巧。

const obj1 = {
  data: ['value1', 'value2']
}
const obj2 = {
  data: [1, 2]
}
// 遍歷方法
consoleEachData = (obj) => {
  obj[Symbol.iterator] = () => {
    let index = 0;
    return {
      next: () => {
        if (index < obj.data.length) {
          return {
            value: obj.data[index++],
            done: false
          };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
  for (const value of obj) {
    console.log(value);
  }
}
consoleEachData(obj1); // value1 value2
consoleEachData(obj2); // 1  2

一點(diǎn)補(bǔ)充

??在寫這篇文章時(shí)咙冗,有個(gè)問(wèn)題給我?guī)?lái)了困擾:原生object對(duì)象默認(rèn)沒有部署Iterator接口沾歪,即object不是一個(gè)可迭代對(duì)象,那么雾消,原生object對(duì)象的解構(gòu)賦值是怎么樣一種機(jī)制呢灾搏?
??有一種說(shuō)法是:ES6提供了Map數(shù)據(jù)結(jié)構(gòu),實(shí)際上原生object對(duì)象被解構(gòu)時(shí)仪或,會(huì)被當(dāng)作Map進(jìn)行解構(gòu)确镊。關(guān)于這點(diǎn),大家有什么不同的觀點(diǎn)嗎范删?歡迎評(píng)論區(qū)一起探討蕾域。

參考資料

本文首發(fā)于個(gè)人博客,歡迎指正和star

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旨巷,一起剝皮案震驚了整個(gè)濱河市巨缘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌采呐,老刑警劉巖若锁,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異斧吐,居然都是意外死亡又固,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門煤率,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仰冠,“玉大人,你說(shuō)我怎么就攤上這事蝶糯⊙笾唬” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵昼捍,是天一觀的道長(zhǎng)识虚。 經(jīng)常有香客問(wèn)我,道長(zhǎng)妒茬,這世上最難降的妖魔是什么担锤? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮郊闯,結(jié)果婚禮上妻献,老公的妹妹穿的比我還像新娘蛛株。我一直安慰自己团赁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布谨履。 她就那樣靜靜地躺著欢摄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪笋粟。 梳的紋絲不亂的頭發(fā)上怀挠,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音害捕,去河邊找鬼绿淋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛尝盼,可吹牛的內(nèi)容都是我干的吞滞。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼裁赠!你這毒婦竟也來(lái)了殿漠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤佩捞,失蹤者是張志新(化名)和其女友劉穎绞幌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體一忱,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡莲蜘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帘营。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菇夸。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖仪吧,靈堂內(nèi)的尸體忽然破棺而出庄新,到底是詐尸還是另有隱情,我是刑警寧澤薯鼠,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布择诈,位于F島的核電站,受9級(jí)特大地震影響出皇,放射性物質(zhì)發(fā)生泄漏羞芍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一郊艘、第九天 我趴在偏房一處隱蔽的房頂上張望荷科。 院中可真熱鬧,春花似錦纱注、人聲如沸畏浆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刻获。三九已至,卻和暖如春瞎嬉,著一層夾襖步出監(jiān)牢的瞬間蝎毡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工氧枣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沐兵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓便监,卻偏偏與公主長(zhǎng)得像扎谎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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

  • ## 前言 &emsp;&emsp;將依據(jù)自身痛點(diǎn)學(xué)習(xí)簿透,計(jì)劃對(duì)原生JavaScript寫一個(gè)系統(tǒng)移袍,本文為第一篇,感...
    Pine_649e閱讀 216評(píng)論 0 0
  • 迭代器 遍歷器(Iterator)是一種接口老充,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問(wèn)機(jī)制葡盗。任何數(shù)據(jù)結(jié)構(gòu)只要部署 Ite...
    漓漾li閱讀 619評(píng)論 0 2
  • 文章內(nèi)容分兩部分: 前半部分為 “迭代器模式” 概念; 后半部分為 ES6 中 Iterator (迭代器) 上半...
    以樂(lè)之名閱讀 525評(píng)論 0 2
  • 迭代器是一種設(shè)計(jì)模式啡浊,它是一個(gè)對(duì)象觅够,它可以遍歷并選擇序列中的對(duì)象,而開發(fā)人員不需要了解該序列的底層結(jié)構(gòu)巷嚣。迭代器通常...
    BenBonBen閱讀 319評(píng)論 0 0
  • 好久沒發(fā)文章啦-喘先。-為了證明我還活著,我決定從筆記里面抓一篇還算不亂比較像文章的發(fā)出來(lái)廷粒。窘拯。。 這些筆記是我在學(xué)es...
    風(fēng)飛揚(yáng)閱讀 329評(píng)論 0 0