最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript中的迭代器和可迭代對(duì)象與生成器

 更新時(shí)間:2022年09月16日 14:28:01   作者:一只小ice???????  
這篇文章主要介紹了JavaScript中的迭代器和可迭代對(duì)象與生成器,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

1. 什么是迭代器?

概念: 迭代器(iterator),是確使用戶可在容器對(duì)象(container,例如鏈表或數(shù)組)上遍訪的對(duì)象[1][2][3],設(shè)計(jì)人員使用此接口無需關(guān)心容器對(duì)象的內(nèi)存分配的實(shí)現(xiàn)細(xì)節(jié)。
JS中的迭代器

  • 其本質(zhì)就是一個(gè)對(duì)象,符合迭代器協(xié)議(iterator protocol)
  • 迭代器協(xié)議

    其對(duì)象返回一個(gè)next函數(shù)

    調(diào)用next函數(shù)返回一個(gè)對(duì)象,其對(duì)象中包含兩個(gè)屬性
    • done(完成),它的值為布爾類型,也就是true/false。
      • 如果這個(gè)迭代器沒有迭代完成即返回{done:false}
      • 當(dāng)這個(gè)迭代器完成了即返回{done:true}
    • value(值),它可以返回js中的任何值,TS中表示可為:value:any類型

1.1 迭代器的基本實(shí)現(xiàn)

思考以下代碼:

let index = 0
const bears = ['ice', 'panda', 'grizzly']

let iterator = {
  next() {
    if (index < bears.length) {
      return { done: false, value: bears[index++] }
    }

    return { done: true, value: undefined }
  }
}
console.log(iterator.next()) //{ done: false, value: 'ice' }
console.log(iterator.next()) //{ done: false, value: 'panda' }
console.log(iterator.next()) //{ done: false, value: 'grizzly' }
console.log(iterator.next()) //{ done: true, value: undefined }
  • 是一個(gè)對(duì)象,實(shí)現(xiàn)了next方法,next方法返回了一個(gè)對(duì)象,有done屬性和value屬性,且key的值類型也為booleanany,符合迭代器協(xié)議,是一個(gè)妥妥的迭代器沒跑了。
  • 弊端
    • 違背了高內(nèi)聚思想,明明indexiterator對(duì)象是屬于一個(gè)整體,我卻使用了全局變量,從V8引擎的GC,可達(dá)性(也就是標(biāo)記清除)來看,如果bears = null ,不手動(dòng)設(shè)置為null很有可能會(huì)造成內(nèi)存泄漏,并且內(nèi)聚性低。
    • 假如我要?jiǎng)?chuàng)建一百個(gè)迭代器對(duì)象呢? 那我就自己定義一百遍嗎?肯定錯(cuò)誤的,我們要把它封裝起來,這樣內(nèi)聚性又高,又能進(jìn)行復(fù)用,一舉兩得,一石二鳥,真的是very beautiful,very 優(yōu)雅。

1.2 迭代器的封裝實(shí)現(xiàn)

思考一下代碼:

const bears = ['ice', 'panda', 'grizzly']

function createArrIterator(arr) {
  let index = 0

  let _iterator = {
    next() {
      if (index < arr.length) {
        return { done: false, value: arr[index++] }
      }

      return { done: true, value: undefined }
    }
  }
  return _iterator
}
let iter = createArrIterator(bears)

console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
  • 內(nèi)聚性非常高,盡最大可能進(jìn)行了復(fù)用,減少冗余代碼

2. 什么是可迭代對(duì)象

迭代器對(duì)象和可迭代對(duì)象是一個(gè)不同的東西,雖然它們存在關(guān)聯(lián),而且面試的時(shí)候經(jīng)常面這些概念,廢話不多說,我們直接進(jìn)入主題。

  • 首先就是一個(gè)對(duì)象,且符合可迭代對(duì)象協(xié)議(iterable protocol)
  • 可迭代對(duì)象協(xié)議

    實(shí)現(xiàn)了[Symbol.iterator]為key的方法,且這個(gè)方法返回了一個(gè)迭代器對(duì)象

  • 繞了一大圈終于把概念搞明白了,那可迭代對(duì)象有什么好處呢? 有什么應(yīng)用場(chǎng)景呢?

    for of 的時(shí)候,其本質(zhì)就是調(diào)用的這個(gè)函數(shù),也就是[Symbol.iterator]為key的方法

2.1 原生可迭代對(duì)象(JS內(nèi)置)

  • String
  • Array
  • Set
  • NodeList 類數(shù)組對(duì)象
  • Arguments 類數(shù)組對(duì)象
  • Map

2.1.1 部分for of 演示

let str = 'The Three Bears'

const bears = ['ice', 'panda', 'grizzly']

for( let text of str) {
  console.log(text) //字符串每個(gè)遍歷打印
}

for( let bear of bears) {
  console.log(bear)
}
 //ice panda grizzly

2.1.2 查看內(nèi)置的[Symbol.iterator]方法

  • 上面給大家舉例了很多可迭代對(duì)象,那它們必定是符合可迭代對(duì)象協(xié)議的,思考以下代碼
const bears = ['ice', 'panda', 'grizzly']
//數(shù)組的Symbol.iterator方法
const iter = bears[Symbol.iterator]()

console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())

const nickName = 'ice'
//字符串的Symbol.iterator方法
const strIter = nickName[Symbol.iterator]()

console.log(strIter.next())
console.log(strIter.next())
console.log(strIter.next())
console.log(strIter.next())

2.2 可迭代對(duì)象的實(shí)現(xiàn)

let info = {
  bears: ['ice', 'panda', 'grizzly'],
  [Symbol.iterator]: function() {
    let index = 0
    let _iterator = {
       //這里一定要箭頭函數(shù),或者手動(dòng)保存上層作用域的this
       next: () => {
        if (index < this.bears.length) {
          return { done: false, value: this.bears[index++] }
        }
  
        return { done: true, value: undefined }
      }
    }

    return _iterator
  }
}

let iter = info[Symbol.iterator]()
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())

//符合可迭代對(duì)象協(xié)議 就可以利用 for of 遍歷
for (let bear of info) {
  console.log(bear)
}
//ice panda grizzly
  • 符合可迭代對(duì)象協(xié)議,是一個(gè)對(duì)象,有[Symbol.iterator]方法,并且這個(gè)方法返回了一個(gè)迭代器對(duì)象。
  • 當(dāng)我利用for of 遍歷,就會(huì)自動(dòng)的調(diào)用這個(gè)方法。

2.3 可迭代對(duì)象的應(yīng)用

  • for of
  • 展開語法
  • 解構(gòu)語法
  • promise.all(iterable)
  • promise.race(iterable)
  • Array.from(iterable)
  • ...

2.4 自定義類迭代實(shí)現(xiàn)

class myInfo {
  constructor(name, age, friends) {
    this.name = name
    this.age = age
    this.friends = friends
  }

  [Symbol.iterator]() {
    let index = 0

    let _iterator = {
      next: () => {
        const friends = this.friends
        if (index < friends.length) {
          return {done: false, value: friends[index++]}
        }

        return {done: true, value: undefined}
      }
    }

    return _iterator
  }
}
const info = new myInfo('ice', 22, ['panda','grizzly'])

for (let bear of info) {
  console.log(bear)
}
//panda
//grizzly
  • 此案例只是簡單的對(duì)friends進(jìn)行了迭代,你也可以迭代你想要的一切東西...
  • 記住此案例,后續(xù)我們會(huì)對(duì)這個(gè)案例進(jìn)行重構(gòu),優(yōu)雅的會(huì)讓你不能用言語來形容。

3. 生成器函數(shù)

生成器是ES6新增的一種可以對(duì)函數(shù)控制的方案,能靈活的控制函數(shù)的暫停執(zhí)行,繼續(xù)執(zhí)行等。

生成器函數(shù)和普通函數(shù)的不同

  • 定義: 普通函數(shù)function定義,生成器函數(shù)function*,要在后面加*
  • 生成器函數(shù)可以通過 yield 來控制函數(shù)的執(zhí)行
  • 生成器函數(shù)返回一個(gè)生成器(generator),生成器是一個(gè)特殊的迭代器

3.1 生成器函數(shù)基本實(shí)現(xiàn)

function* bar() {
  console.log('fn run')
}

bar()
  • 我們會(huì)發(fā)現(xiàn),這個(gè)函數(shù)竟然沒有執(zhí)行。我們前面說過,它是一個(gè)生成器函數(shù),它的返回值是一個(gè)生成器,同時(shí)也是一個(gè)特殊的迭代器,所以跟普通函數(shù)相比,好像暫停了,那如何讓他執(zhí)行呢?接下來我們進(jìn)一步探討。

3.2 生成器函數(shù)單次執(zhí)行

function* bar() {
  console.log('fn run')
}

const generator = bar()

console.log(generator.next())
//fn run
//{ value: undefined, done: true }
  • 返回了一個(gè)生成器,我們調(diào)用next方法就可以讓函數(shù)執(zhí)行,并且next方法是有返回值的,我們上面講迭代器的時(shí)候有探討過,而value沒有返回值那就是undefined。那上面說的yield關(guān)鍵字在哪,到底是如何控制函數(shù)的呢?是如何用的呢?

3.3 生成器函數(shù)多次執(zhí)行

function* bar() {
  console.log('fn run start')
  yield 100
  console.log('fn run...')
  yield 200
  console.log('fn run end')
  return 300
}

const generator = bar()

//1. 執(zhí)行到第一個(gè)yield,暫停之后,并且把yield的返回值 傳入到value中
console.log(generator.next())
//2. 執(zhí)行到第一個(gè)yield,暫停之后,并且把yield的返回值 傳入到value中
console.log(generator.next())
//3. 執(zhí)行剩余代碼
console.log(generator.next())

//打印結(jié)果:
//fn run start
//{done:false, value: 100}
//fn run...
//{done:false, value: 200}
//fn run end
//{done:true, value: 300}
  • 現(xiàn)在我們恍然大悟,每當(dāng)調(diào)用next方法的時(shí)候,代碼就會(huì)開始執(zhí)行,執(zhí)行到yield x,后就會(huì)暫停,等待下一次調(diào)用next繼續(xù)往下執(zhí)行,周而復(fù)始,沒有了yield關(guān)鍵字,進(jìn)行最后一次next調(diào)用返回done:true

3.4 生成器函數(shù)的分段傳參

我有一個(gè)需求,既然生成器能控制函數(shù)分段執(zhí)行,我要你實(shí)現(xiàn)一個(gè)分段傳參。

思考以下代碼:

function* bar(nickName) {
  const str1 = yield nickName
  const str2 = yield str1 + nickName
  return str2 + str1 + nickName
}
const generator = bar('ice')
console.log(generator.next())
console.log(generator.next('panda '))
console.log(generator.next('grizzly '))
console.log(generator.next())

// { value: 'ice', done: false }
// { value: 'panda ice', done: false }
// { value: 'grizzly panda ice', done: true }
// { value: undefined, done: true }
  • 如果沒有接觸過這樣的代碼會(huì)比較奇怪
    • 當(dāng)我調(diào)用next函數(shù)的時(shí)候,yield的左側(cè)是可以接受參數(shù)的,也并不是所有的next方法的實(shí)參都能傳遞到生成器函數(shù)內(nèi)部
    • yield左側(cè)接收的,是第二次調(diào)用next傳入的實(shí)參,那第一次傳入的就沒有yield關(guān)鍵字接收,所有只有當(dāng)我調(diào)用bar函數(shù)的時(shí)候傳入。
    • 最后一次next調(diào)用,傳入的參數(shù)我也調(diào)用不了,因?yàn)闆]有yield關(guān)鍵字可以接收了。
  • 很多開發(fā)者會(huì)疑惑,這樣寫有什么用呢? 可讀性還差,但是在處理異步數(shù)據(jù)的時(shí)候就非常有用了,后續(xù)會(huì)在promise中文章中介紹。

3.5 生成器代替迭代器

前面我們講到,生成器是一個(gè)特殊的迭代器,那生成器必定是可以代替迭代器對(duì)象的,思考以下代碼。

let bears = ['ice','panda','grizzly']

function* createArrIterator(bears) {
  for (let bear of bears) {
    yield bear
  }
}
const generator = createArrIterator(bears)
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())

其實(shí)這里還有一種語法糖的寫法yield*

  • yield* 依次迭代這個(gè)可迭代對(duì)象,相當(dāng)于遍歷拿出每一項(xiàng) yield item(偽代碼)

思考以下代碼:

let bears = ['ice','panda','grizzly']

function* createArrIterator(bears) {
  yield* bears
}
const generator = createArrIterator(bears)
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
  • 依次迭代這個(gè)可迭代對(duì)象,返回每個(gè)item值

4. 可迭代對(duì)象的終極封裝

class myInfo {
  constructor(name, age, friends) {
    this.name = name
    this.age = age
    this.friends = friends
  }
  *[Symbol.iterator]() {
    yield* this.friends
  }
}
const info = new myInfo('ice', 22, ['panda','grizzly'])
for (let bear of info) {
  console.log(bear)
}

//panda
//grizzly
  • 回顧以下可迭代對(duì)象協(xié)議
    • 是一個(gè)對(duì)象并且有[Symbol.iterator]方法
    • 這個(gè)方法返回一個(gè)迭代器對(duì)象 生成器函數(shù)返回一個(gè)生成器,是一個(gè)特殊的迭代器

5. 總結(jié)

5.1 迭代器對(duì)象

  • 本質(zhì)就是一個(gè)對(duì)象,要符合迭代器協(xié)議
  • 有自己對(duì)應(yīng)的next方法,next方法則返回一組數(shù)據(jù){done:boolean, value:any}

5.2 可迭代對(duì)象

  • 本質(zhì)就是對(duì)象,要符合可迭代對(duì)象協(xié)議
  • [Symbol.iterator]方法,并且調(diào)用這個(gè)方法返回一個(gè)迭代器

5.3 生成器函數(shù)

  • 可以控制函數(shù)的暫停執(zhí)行和繼續(xù)執(zhí)行
  • 通過function* bar() {} 這種形式定義
  • 不會(huì)立馬執(zhí)行,而是返回一個(gè)生成器,生成器是一個(gè)特殊的迭代器對(duì)象
  • yield 關(guān)鍵字可以控制函數(shù)分段執(zhí)行
  • 調(diào)用返回生成器的next方法進(jìn)行執(zhí)行

到此這篇關(guān)于JavaScript中的迭代器和可迭代對(duì)象與生成器的文章就介紹到這了,更多相關(guān)JavaScript迭代器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript SHA1加密算法實(shí)現(xiàn)詳細(xì)代碼

    JavaScript SHA1加密算法實(shí)現(xiàn)詳細(xì)代碼

    這篇文章主要為大家詳細(xì)介紹了JavaScript SHA1加密算法實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的朋友可以參考一下
    2016-10-10
  • echart在微信小程序的使用簡單示例

    echart在微信小程序的使用簡單示例

    最近公司的項(xiàng)目中需要在小程序內(nèi)使用echarts組件來展示數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于echart在微信小程序的使用方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • JSON.stringify的多種用法總結(jié)

    JSON.stringify的多種用法總結(jié)

    這篇文章主要給大家介紹了關(guān)于JSON.stringify使用的相關(guān)資料, JSON.stringify()方法是將一個(gè)JavaScript值(對(duì)象或者數(shù)組)轉(zhuǎn)換為一個(gè) JSON字符串,需要的朋友可以參考下
    2021-06-06
  • JavaScript的console命令使用實(shí)例

    JavaScript的console命令使用實(shí)例

    這篇文章主要介紹了javascript的console命令使用實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • D3.js 實(shí)現(xiàn)帶伸縮時(shí)間軸拓?fù)鋱D的示例代碼

    D3.js 實(shí)現(xiàn)帶伸縮時(shí)間軸拓?fù)鋱D的示例代碼

    這篇文章主要介紹了D3.js 實(shí)現(xiàn)帶伸縮時(shí)間軸拓?fù)鋱D的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • JavaScript圖片的Base64編碼以及轉(zhuǎn)換詳解

    JavaScript圖片的Base64編碼以及轉(zhuǎn)換詳解

    現(xiàn)在網(wǎng)站為了提升用戶的瀏覽體驗(yàn)越來越多的使用了圖片,而這些圖片通常以 Base64 的形式存儲(chǔ)和加載,下面這篇文章主要給大家介紹了關(guān)于JavaScript圖片的Base64編碼以及轉(zhuǎn)換的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • 簡單實(shí)用的反饋表單無刷新提交帶驗(yàn)證

    簡單實(shí)用的反饋表單無刷新提交帶驗(yàn)證

    表單無刷新提交帶驗(yàn)證,非常適用于反饋,具體的實(shí)現(xiàn)如下包含各個(gè)功能代碼,喜歡的朋友可以參考下
    2013-11-11
  • 詳解微信小程序 頁面跳轉(zhuǎn) 傳遞參數(shù)

    詳解微信小程序 頁面跳轉(zhuǎn) 傳遞參數(shù)

    這篇文章主要介紹了詳解微信小程序 頁面跳轉(zhuǎn) 傳遞參數(shù),現(xiàn)在分享給大家,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2016-12-12
  • JavaScript獲取當(dāng)前網(wǎng)頁標(biāo)題(title)的方法

    JavaScript獲取當(dāng)前網(wǎng)頁標(biāo)題(title)的方法

    這篇文章主要介紹了JavaScript獲取當(dāng)前網(wǎng)頁標(biāo)題(title)的方法,涉及javascript中document.title方法的使用,需要的朋友可以參考下
    2015-04-04
  • 在視頻前插入廣告

    在視頻前插入廣告

    在視頻前插入廣告...
    2006-11-11

最新評(píng)論

射阳县| 扎赉特旗| 林口县| 昭通市| 高青县| 蒙城县| 天台县| 府谷县| 萝北县| 文水县| 汤阴县| 梧州市| 阿拉善左旗| 太湖县| 西平县| 哈巴河县| 启东市| 固阳县| 图木舒克市| 岢岚县| 湟源县| 张家川| 井陉县| 色达县| 福鼎市| 包头市| 舟曲县| 靖边县| 罗源县| 江阴市| 房山区| 宝鸡市| 满城县| 宜昌市| 怀宁县| 贺州市| 万年县| 宝应县| 玉林市| 界首市| 四会市|