中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JS前端使用迭代器和生成器原理是什么

發布時間:2023-02-22 17:36:35 來源:億速云 閱讀:146 作者:iii 欄目:開發技術

這篇文章主要介紹了JS前端使用迭代器和生成器原理是什么的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇JS前端使用迭代器和生成器原理是什么文章都會有所收獲,下面我們一起來看看吧。

正文

生成器和迭代器這兩個東西平時作為一個切圖仔,一直都沒有使用到。感覺是只有在面試之前才會的東西。面試過不了幾天,再次看這兩個詞一陣恍惚。

記憶力退化成這樣了么?最大的原因一定是用得少了。然后呢?就是沒有真正的理解它們。我對于它們的認知常常有下面這些:

1. 我常常把迭代器和生成器理解成完全不同的東西。

2. 我常常把for、forEach、map、reducefor of混為一談

3. 我常常把數組、類數組認為是可迭代對象

想來要真正的記住它,增加自己的武器庫,必須要弄明白這些東西才行。

我們首先是要搞明白什么for of是干什么用的。

業務代碼確實使用不上,但是如果不理解的話,等真到了可以使用的場景的時候,又是否真的能夠運用起來,甚至記起來呢?

for of 是干什么用的

所有人都知道一些概念for、forEach、map、reduce這些是可以遍歷數組的,for of是用于遍歷迭代對象的。如下:

const arr = [1, 2, 3]
arr.forEach((item, index) => {
   console.log(item) // 1, 2, 3 
   console.log(index) // 0, 1, 2
})

而巧合的是for of也可以遍歷數組

for (let key of arr) {
    console.log(key) // 1 2 3
}

將arr改變為const obj = { a: 1, b: 2, c: 3 }的時候,兩者都沒有遍歷出結果。

前者是沒有反應,后者會直接報錯:TypeError: obj is not iterable。翻譯一下,類型錯誤:obj 不是一個可迭代對象。

那么什么是可迭代對象呢?

可迭代對象是什么?

我們先來看看下面這個例子:

const itemLi1 = document.getElementByTagName('li')
const itemLi2 = document.querySelectorAll('li')
for(let key of itemLi1) {
    console.log(item)
}
for(let key of itemLi2) {
    console.log(item)
}

也就是說HTMLCollectionNodeList是可以迭代對象。其他的可迭代對象有Array、map、set、string等等。如果說類數組的話,是不是迭代對象呢?

const arrLike = {
  0: 1,
  1: 2,
  2: 3,
  lenght: 3
}
for (let i = 0; i < arrLike.length; i++) {
    console.log(arrLike[i]) // 1, 2, 3
}
for (let of arrLike) {
    console.log(key) // uncachh TypeError: obj is not iterable
}

for循環打印出了對應的結果,而for of 報錯了。類數組不是可迭代的的對象。這又是為什么呢?我們將類數組和HTMLCollection類型打印出來比較一下。

JS前端使用迭代器和生成器原理是什么

而類數組如下:

JS前端使用迭代器和生成器原理是什么

它們有一個明顯的不同,可迭代對象的原型鏈上面是包括Symbol.iterator的。而這個就是讓數組變成可迭代的根本原因。

也就是說,當目的對象的原型鏈上面包括Symbol.iterator的時候,它才是可迭代對象。

對象是無序的,無序的東西自然不可以迭代

這里使用到了Symbol類型,它在MDN上面的解釋就是用于生成全局唯一的變量。而可迭代對象就是它的使用場景。受它的啟發,我們在業務當中,如果需要前端來生成一個唯一ID的時候,再次之前,通常都是創建一個UUID的函數來生成一個唯一ID。Symbol不用這么麻煩,直接使用就可以了。

由此可知,Array.prototype[Symbol.iterater]這個函數封裝了一些東西,使得for of可以將對象的元素給打印出來。

換一句話來說,就是Array.prototype[Symbol.iterater] = function() {}的執行生成一個迭代器對象。

也就是說,當Object.prototype也有[Symbol.iterater]的方法的時候,for of也能夠遍歷它呢?我們來試試看吧。

Object.ptotoype[Symbol.iterator] = function value() {}

這不就是生成器的作用么?

生成器和迭代器的關系。

ES6給我提高了一個生成器的函數。既然叫做生成器,它生成的東西就是迭代器。

表現形式如下:

function * generation(iterableObject) {
    for(let i = 0; i < iterableObject; i++) {
        yield iterableObject[i]
    }
}

*符號和yield關鍵字組成。

const iterator = generation([1, 2, 3]), 其執行流程如下:

iterator.next() ==> { value: 1, done: false }

iterator.next() ==> { value: 2, done: false }

iterator.next() ==> { value: 3, done: false }

iterator.next() ==> { value: undefined, done: true }

到了第四次,value為undefined的時候,done為true(也就是說,當done為true的時候,value一定為undefined)。所以說,yield的作用有兩個:

  • 生成一個值,將該值封裝成一個對象,而這個對象是{ value: .., done: flase/true }這樣的形式。

  • 停下來

可以明顯的看出來,生成器有一個作用,通過next這個接口,可以看到迭代的過程。

既然說生成器生成了一個迭代器,那么是不是說生成器執行后的結果就是一個迭代器呢?既然是迭代器,自然就可以被for of給遍歷。

for (const key of generation([1, 2, 3]) {
    console.log(key) // 1, 2, 3
}

果然可以。

經典面試題: 自己實現一個next這樣的接口呢?

上面已經有了實現的思路。通過一個標識符和一個判斷就能夠使用ES5來使用,如下代碼片段。

function generation(iterableObj) {
    let nextIndex = 0
    function next() {}
    return {
        next: () => {
            return nextIndex < iterableObj.length
                             ? { value: iterableObj[nextIndex++], done: false }
                             : { value: undefined, done: true } 
        }
    }
}

當nextIndex下于數組長度的時候,沒有迭代完畢。

注意:nextIndex++是先跑nextIndex,再自增。

何為接口,后臺給你一個url地址,這個是網絡接口。next是設計師給你封裝的一個方法,你通過這個方法來達到上吧yield的兩個作用,所以next()也是一個接口,前端接口。簡單來說,一個封裝好的方法就是一個接口。

讓非迭代對象也可以使用for of 進行遍歷

正如第一節所說,Symbol.iterator的方法是迭代器的關鍵。那么我們也可以給Object掛載上該方法。既然該方法可以讓對象變成迭代器,就可以直接使用上面ES5實現next方法的代碼片段。

const obj = {
  a: 1,
  b: 2,
  c: 3
}
Object.prototype[Symbol.iterator] = function value() {
  const keys = Object.keys(Object(this))
  let nextIndex = 0
  function next() {
    return nextIndex < keys.length
        ? { value: [keys[nextIndex], obj[keys[nextIndex ++]]], done: false }
        : { value: undefined, done: true }
  }
  return {
    next
  }
}
for (const [key, value] in obj) {
  console.log(key)
}

for循環和for in的關系

for循環和for in 看著很像,其實只是共用了for這個關鍵字,它們都是JS引擎底層實現的東西。和forEach、map這些是基于for循環的API不同,它們是在實現在for循環之上的。

關于“JS前端使用迭代器和生成器原理是什么”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“JS前端使用迭代器和生成器原理是什么”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

js
AI

滦南县| 辽阳县| 旺苍县| 天等县| 河曲县| 宿松县| 尚义县| 房产| 峨眉山市| 湘阴县| 临湘市| 乌拉特前旗| 尚义县| 崇阳县| 阳泉市| 柳江县| 扶余县| 文安县| 海盐县| 遵化市| 兴安县| 察隅县| 常熟市| 巴东县| 苍梧县| 漾濞| 澎湖县| 富裕县| 松溪县| 鄢陵县| 建始县| 滨州市| 郯城县| 蒙城县| 浦东新区| 勃利县| 台州市| 凉山| 武宣县| 邹城市| 浦城县|