JavaScript中的惰性數(shù)組介紹
今天我要介紹的是 lazy-arr ,它給JavaScript中帶來了惰性數(shù)組。
什么是惰性數(shù)組,它為什么有用?我們來重現(xiàn)一下你第一次面試軟件工程師時(shí)的題目:寫一個(gè)斐波納契函數(shù)。我們明確了0和1的基本情況,然后遞歸生成剩下的:
let fib = n => { switch (n) { case 0: return 0 case 1: return 1 default: return fib(n - 1) + fib(n - 2) }}
小菜一碟。
這種解決方案有什么問題嗎?還用說么 - 效率真的真的很低。要計(jì)算第n個(gè)斐波那契數(shù)字,我們要調(diào)用 fib 函數(shù) 2的n-1冪次!簡直糟糕的要命,我們應(yīng)該做的更好一點(diǎn)。
一種方法是記錄 fib 的輸出。就是說,由于 fib 是純粹和冪等的,我們可以緩存其輸出:
let memoize = fn => { let cache = new Map return _ => { if (!cache.has(_)) { cache.set(_, fn(_)) } return cache.get(_) }}let fib = memoize(n => { switch (n) { case 0: return 0 case 1: return 1 default: return fib(n - 1) + fib(n - 2) }})
好多了!現(xiàn)在我們輸入為n時(shí),只需調(diào)用 fib n - 1次。
我們還能怎么表達(dá)這種思想呢?
懶序列在Scale中,你可以這樣做(這得歸功于 Philipp Gabler ):
def fib(n: Int): Stream[Int] = { lazy val stream: Stream[Int] = 0 #:: stream.scan(1)(_ + _) stream.take(n)}
上面做的事情就是定義一個(gè)惰性的數(shù)據(jù)流(兩個(gè)初始數(shù)字,加上一個(gè)能產(chǎn)生更多數(shù)字的函數(shù)),當(dāng)調(diào)用 fib(n) 時(shí),它返回第n個(gè)數(shù)字,或者如果還沒有計(jì)算,就生成并返回它。另一種思考方式是用生成器和一個(gè)記錄先前產(chǎn)生值的緩存,這樣之后就可以通過值的索引進(jìn)行訪問。
惰性流是一個(gè)非常酷的抽象概念,對(duì)于計(jì)算開銷昂貴的序列,或者是不可能計(jì)算所有索引的序列都有效(即:無限序列)。這在功能性語言中很受歡迎,特別是默認(rèn)具有惰性求值的語言。比如在Haskell中就是這樣做:
fibs :: [Integer]fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
同樣的思維,但在Clojure就是這樣:
(defn fib [] ((fn rfib [a b](cons a (lazy-seq (rfib b (+ a b))))) 0 1))
你大概明白了吧。
那在JavaScript中怎么用呢?
JavaScript中的惰性序列通過 lazy-arr ,你可以像這樣:
let fibs = lazy([0, 1])(_ => fibs[_ - 1] + fibs[_ - 2])
就這樣!然后,您可以根據(jù)需要訪問數(shù)組中的項(xiàng),并根據(jù)需要進(jìn)行計(jì)算:
fibs[10] // 55fibs[7] // 13
第一行計(jì)算第10個(gè)斐波納契數(shù),并且由于我們遞歸地進(jìn)行計(jì)算的定義(按照以前的斐波那契數(shù)),我們需要計(jì)算前9個(gè)斐波那契數(shù),以此來計(jì)算第10個(gè)。所以當(dāng)我們?cè)诘诙杏?jì)算第七個(gè)斐波納契數(shù)時(shí),結(jié)果會(huì)立即返回,因?yàn)槲覀円呀?jīng)計(jì)算好了!
最重要的是,就用戶關(guān)心的來說, fibs 數(shù)組并不會(huì)做任何懈怠地、有狀態(tài)地或遞歸地或其他類似的事情。它只是一個(gè)數(shù)組。那些麻煩的東西被lazy-arr封裝好了,生成器就是一行代碼。
是不是很優(yōu)雅?
來自:http://www.zcfy.cc/article/performancejs-introducing-lazy-arrays-in-javascript-3312.html
相關(guān)文章:
1. Android table布局開發(fā)實(shí)現(xiàn)簡單計(jì)算器2. jQuery 實(shí)現(xiàn)DOM元素拖拽交換位置的實(shí)例代碼3. 理解PHP5中static和const關(guān)鍵字4. php模擬實(shí)現(xiàn)斗地主發(fā)牌5. IntelliJ IDEA安裝插件的方法步驟6. spring acegi security 1.0.0 發(fā)布7. Vue封裝一個(gè)TodoList的案例與瀏覽器本地緩存的應(yīng)用實(shí)現(xiàn)8. Python random庫使用方法及異常處理方案9. .Net Core使用Coravel實(shí)現(xiàn)任務(wù)調(diào)度的完整步驟10. Vuex localStorage的具體使用

網(wǎng)公網(wǎng)安備