日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
JavaScriptLazyevaluation:可迭代對象與迭代器

本文已經(jīng)過原作者 MelkorNemesis 授權(quán)翻譯。

10多年專注成都網(wǎng)站制作,成都企業(yè)網(wǎng)站建設(shè),個人網(wǎng)站制作服務(wù),為大家分享網(wǎng)站制作知識、方案,網(wǎng)站設(shè)計流程、步驟,成功服務(wù)上千家企業(yè)。為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁設(shè)計及定制高端網(wǎng)站建設(shè)服務(wù),專注于成都企業(yè)網(wǎng)站建設(shè),高端網(wǎng)頁制作,對成都自上料攪拌車等多個方面,擁有多年的網(wǎng)站運維經(jīng)驗。

Lazy evaluation

Lazy evaluation常被譯為“延遲計算”或“惰性計算”,指的是僅僅在真正需要執(zhí)行的時候才計算表達式的值。

與惰性求值相反的是及早求值(eager evaluation)及早求值,也被稱為貪婪求值(greedy evaluation)或嚴格求值,是多數(shù)傳統(tǒng)編程語言的求值策略。

充分利用惰性求值的特性帶來的好處主要體現(xiàn)在以下兩個方面:

  • 避免不必要的計算,帶來性能上的提升。
  • 節(jié)省空間,使得無限循環(huán)的數(shù)據(jù)結(jié)構(gòu)成為可能。

迭代器

ES6 中的迭代器使惰性求值和創(chuàng)建用戶定義的數(shù)據(jù)序列成為可能。迭代是一種遍歷數(shù)據(jù)的機制。迭代器是用于遍歷數(shù)據(jù)結(jié)構(gòu)元素(稱為Iterable)的指針,用于產(chǎn)生值序列的指針。

迭代器是一個可以被迭代的對象。它抽象了數(shù)據(jù)容器,使其行為類似于可迭代對象。

迭代器在實例化時不計算每個項目的值,僅在請求時才生成下一個值。這非常有用,特別是對于大型數(shù)據(jù)集或無限個元素的序列。

可迭代對象

可迭代對象是希望其元素可被公眾訪問的數(shù)據(jù)結(jié)構(gòu)。JS 中的很多對象都是可迭代的,它們可能不是很好的察覺,但是如果仔細檢查,就會發(fā)現(xiàn)迭代的特征:

  • new Map([iterable])
  • new WeakMap([iterable])
  • new Set([iterable])
  • new WeakSet([iterable])
  • Promise.all([iterable])
  • Promise.race([iterable])
  • Array.from([iterable])

還有需要一個可迭代的對象,否則,它將拋出一個類型錯誤,例如:

  • for ... of
  • ... (展開操作符)const [a, b, ..] = iterable (解構(gòu)賦值)
  • yield* (生成器)

JavaScript中已有許多內(nèi)置的可迭代項:

String,Array,TypedArray,Map,Set。

迭代協(xié)議

迭代器和可迭對象遵循迭代協(xié)議。

協(xié)議是一組接口,并規(guī)定了如何使用它們。

迭代器遵循迭代器協(xié)議,可迭代遵循可迭代協(xié)議。

可迭代的協(xié)議

要使對象變得可迭代,它必須實現(xiàn)一個通過Symbol.iterator的迭代器方法,這個方法是迭代器的工廠。

使用 TypeScript,可迭代協(xié)議如下所示:

 
 
 
 
  1. interface Iterable {
  2.   [Symbol.iterator]() : Iterator;
  3. }

Symbol.iterator]()是無參數(shù)函數(shù)。在可迭代對象上調(diào)用它,這意味著我們可以通過this來訪問可迭代對象,它可以是常規(guī)函數(shù)或生成器函數(shù)。

迭代器協(xié)議

迭代器協(xié)議定義了產(chǎn)生值序列的標準方法。

為了使對象成為迭代器,它必須實現(xiàn)next()方法。迭代器可以實現(xiàn)return()方法,我們將在本文后面討論這個問題。

使用 TypeScript,迭代器協(xié)議如下所示:

 
 
 
 
  1. interface Iterator {
  2.     next() : IteratorResult;
  3.     return?(value?: any): IteratorResult;
  4. }

IteratorResult 的定義如下:

 
 
 
 
  1. interface IteratorResult {
  2.     value?: any;
  3.     done: boolean;
  4. }
  • done通知消費者迭代器是否已經(jīng)被使用,false表示仍有值需要生成,true表示迭代器已經(jīng)結(jié)束。
  • value 可以是任何 JS 值,它是向消費者展示的值。

當done為true時,可以省略value。

組合

迭代器和可以可迭代對象可以用下面這張圖來表示:

事例

基礎(chǔ)知識介紹完了,接著,我們來配合一些事例來加深我們的映像。

范圍迭代器

我們先從一個非?;镜牡鏖_始,createRangeIterator迭代器。

我們手動調(diào)用it.next()以獲得下一個IteratorResult。最后一次調(diào)用返回{done:true},這意味著迭代器現(xiàn)在已被使用,不再產(chǎn)生任何值。

 
 
 
 
  1. function createRangeIterator(from, to) {
  2.   let i = from;
  3.   return {
  4.     next() {
  5.       if (i <= to) {
  6.         return { value: i++, done: false };
  7.       } else {
  8.         return { done: true };
  9.       }
  10.     }
  11.   }
  12. }
  13. const it = createRangeIterator(1, 3);
  14. console.log(it.next());
  15. console.log(it.next());
  16. console.log(it.next());
  17. console.log(it.next());

可迭代范圍迭代器

在本文的前面,我已經(jīng)提到 JS 中的某些語句需要一個可迭代的對象。因此,我們前面的示例在與for ... of循環(huán)一起使用時將不起作用。

但是創(chuàng)建符合迭代器和可迭代協(xié)議的對象非常容易。

 
 
 
 
  1. function createRangeIterator (from, to) {
  2.   let i = from
  3.   return {
  4.     [Symbol.iterator] () {
  5.       return this
  6.     },
  7.     next() {
  8.       if (i <= to) {
  9.         return { value: i++, done: false }
  10.       } else {
  11.         return { done: true }
  12.       }
  13.     }
  14.   }
  15. }
  16. const it = createRangeIterator(1, 3)
  17. for (const i of it) {
  18.   console.log(i)
  19. }

無限序列迭代器

迭代器可以表示無限制大小的序列,因為它們僅在需要時才計算值。

注意不要在無限迭代器上使用擴展運算符(...),JS 將嘗試消費迭代器,由于迭代器是無限的,因此它將永遠不會結(jié)束。所以你的應(yīng)用程序?qū)⒈罎?,因為?nèi)存已被耗盡 ??

同樣,for ... of 循環(huán)也是一樣的情況,所以要確保能退出循環(huán):

 
 
 
 
  1. function createEvenNumbersIterator () {
  2.   let value = 0
  3.   return {
  4.     [Symbol.iterator] () {
  5.       return this
  6.     },
  7.     next () {
  8.       value += 2
  9.       return { value, done: false}
  10.     }
  11.   }
  12. }
  13. const it = createEvenNumbersIterator()
  14. const [a, b, c] = it
  15. console.log({a, b, c})
  16. const [x, y, z] = it
  17. console.log({ x, y, z })
  18. for (const even of it) {
  19.   console.log(even)
  20.   if (even > 20) {
  21.     break
  22.   }
  23. }

關(guān)閉迭代器

前面我們提到過,迭代器可以有選擇地使用return()方法。當?shù)髦钡阶詈蠖紱]有迭代時使用此方法,并讓迭代器進行清理。

for ... of循環(huán)可以通過以下方式更早地終止迭代:

  • break
  • continue
  • throw
  • return
 
 
 
 
  1. function createCloseableIterator () {
  2.   let idx = 0
  3.   const data = ['a', 'b', 'c', 'd', 'e']
  4.   function cleanup() {
  5.     console.log('Performing cleanup')
  6.   }
  7.   return {
  8.     [Symbol.iterator]() { return this },
  9.     next () {
  10.       if (idx <= data.length - 1) {
  11.         return { value: data[idx++], done: false }
  12.       } else {
  13.         cleanup()
  14.         return { done: true }
  15.       }
  16.     },
  17.     return () {
  18.       cleanup()
  19.       return { done: true }
  20.     }
  21.   }
  22. }
  23. const it = createCloseableIterator()
  24. for (const value of it) {
  25.   console.log(value)
  26.   if (value === 'c') {
  27.     break
  28.   }
  29. }
  30. console.log('\n----------\n')
  31. const _it = createCloseableIterator();
  32. for (const value of _it) {
  33.   console.log(value);
  34. }

  • 如果知道迭代器已經(jīng)結(jié)束,則手動調(diào)用cleanup()函數(shù)。
  • 如果突然完成,則return()起作用并為我們進行清理。

額外的內(nèi)容

如果你已經(jīng)做到了這一點,我們來看看一些額外的內(nèi)容。

組合器

組合器是將現(xiàn)有可迭代對象組合在一起以創(chuàng)建新可迭代對象的函數(shù)。

因此,我們能夠創(chuàng)建許多實用函數(shù)。那map或者filter呢?看看下面的代碼,花一分鐘時間來理解它。

 
 
 
 
  1. function createEvenNumbersIterator() {
  2.   let value = 0;
  3.   return {
  4.     [Symbol.iterator]() {
  5.       return this;
  6.     },
  7.     next() {
  8.       value += 2;
  9.       return { value, done: false };
  10.     }
  11.   }
  12. }
  13. function map(fn, iterable) {
  14.   const iter = iterable[Symbol.iterator]();
  15.   return {
  16.     [Symbol.iterator]() {
  17.       return this;
  18.     },
  19.     next() {
  20.       const n = iter.next();
  21.       if (!n.done) {
  22.         return { value: fn(n.value), done: false };
  23.       } else {
  24.         return { done: true };
  25.       }
  26.     }
  27.   }
  28. }
  29. function filter(fn, iterable) {
  30.   const iter = iterable[Symbol.iterator]();
  31.   return {
  32.     [Symbol.iterator]() {
  33.       return this;
  34.     },
  35.     next() {
  36.       const n = iter.next();
  37.       if (!n.done) {
  38.         if (fn(n.value)) {
  39.           return { value: n.value, done: false };
  40.         } else {
  41.           return this.next();
  42.         }
  43.       } else {
  44.         return { done: true };
  45.       }
  46.     }
  47.   }
  48. }
  49. function take(n, iterable) {
  50.   const iter = iterable[Symbol.iterator]();
  51.   return {
  52.     [Symbol.iterator]() {
  53.       return this;
  54.     },
  55.     next() {
  56.       if (n > 0) {
  57.         n--;
  58.         return iter.next();
  59.       } else {
  60.         return { done: true };
  61.       }
  62.     }
  63.   }
  64. }
  65. function cycle(iterable) {
  66.   const iter = iterable[Symbol.iterator]();
  67.   const saved = [];
  68.   let idx = 0;
  69.   
  70.   return {
  71.     [Symbol.iterator]() {
  72.       return this;
  73.     },
  74.     next() {
  75.       const n = iter.next();
  76.       if (!n.done) {
  77.         saved[idx++] = n.value;
  78.         return { value: n.value, done: false };
  79.       } else {
  80.         return { value: saved[idx++ % saved.length], done: false };
  81.       }
  82.     }
  83.   }
  84. }
  85. function collect(iterable) {
  86.   // consumes the iterator
  87.   return Array.from(iterable);
  88. }
  89. const evenNumbersIterator = createEvenNumbersIterator();
  90. const result = collect(                 // 7. and collect the result
  91.   filter(                               // ?? 6. keep only values higher than 1
  92.     val => val > 1, map(                // ?? 5. divide obtained values by 2
  93.       val => val / 2, take(             // ?? 4. take only six of them
  94.         6, cycle(                       // ?? 3. make an infinite cycling sequence of them
  95.           take(                         // ?? 2. take just three of them
  96.             3, evenNumbersIterator      // ?? 1. infinite sequence of even numbers
  97.           )
  98.         )
  99.       )
  100.     )
  101.   )
  102. );
  103. console.log(result);

這是一大堆代碼,很快我們將看到如何使用生成器和函數(shù)式編程概念來重構(gòu)所有這些內(nèi)容。保持關(guān)注,并注意我的后續(xù)文章,我們?nèi)匀挥泻芏鄡?nèi)容要講。

作者:MelkorNemesis 譯者:前端小智 來源:medium

原文:https://medium.com/@MelrNemesis/javascript-lazy-evaluation-iterables-iterators-e0770a5de96f

本文轉(zhuǎn)載自微信公眾號「 大遷世界」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 大遷世界公眾號。


網(wǎng)頁名稱:JavaScriptLazyevaluation:可迭代對象與迭代器
轉(zhuǎn)載注明:http://m.5511xx.com/article/dhgcdod.html