JavaScript中的惰性數(shù)組介紹
今天我要介紹的是 lazy-arr ,它給JavaScript中帶來(lái)了惰性數(shù)組。
什么是惰性數(shù)組,它為什么有用?我們來(lái)重現(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) }}
小菜一碟。
這種解決方案有什么問(wèn)題嗎?還用說(shuō)么 - 效率真的真的很低。要計(jì)算第n個(gè)斐波那契數(shù)字,我們要調(diào)用 fib 函數(shù) 2的n-1冪次!簡(jiǎn)直糟糕的要命,我們應(yīng)該做的更好一點(diǎn)。
一種方法是記錄 fib 的輸出。就是說(shuō),由于 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ù)字,或者如果還沒(méi)有計(jì)算,就生成并返回它。另一種思考方式是用生成器和一個(gè)記錄先前產(chǎn)生值的緩存,這樣之后就可以通過(guò)值的索引進(jìn)行訪問(wèn)。
惰性流是一個(gè)非常酷的抽象概念,對(duì)于計(jì)算開(kāi)銷昂貴的序列,或者是不可能計(jì)算所有索引的序列都有效(即:無(wú)限序列)。這在功能性語(yǔ)言中很受歡迎,特別是默認(rèn)具有惰性求值的語(yǔ)言。比如在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中的惰性序列通過(guò) lazy-arr ,你可以像這樣:
let fibs = lazy([0, 1])(_ => fibs[_ - 1] + fibs[_ - 2])
就這樣!然后,您可以根據(jù)需要訪問(wèn)數(shù)組中的項(xiàng),并根據(jù)需要進(jìn)行計(jì)算:
fibs[10] // 55fibs[7] // 13
第一行計(jì)算第10個(gè)斐波納契數(shù),并且由于我們遞歸地進(jìn)行計(jì)算的定義(按照以前的斐波那契數(shù)),我們需要計(jì)算前9個(gè)斐波那契數(shù),以此來(lái)計(jì)算第10個(gè)。所以當(dāng)我們?cè)诘诙杏?jì)算第七個(gè)斐波納契數(shù)時(shí),結(jié)果會(huì)立即返回,因?yàn)槲覀円呀?jīng)計(jì)算好了!
最重要的是,就用戶關(guān)心的來(lái)說(shuō), fibs 數(shù)組并不會(huì)做任何懈怠地、有狀態(tài)地或遞歸地或其他類似的事情。它只是一個(gè)數(shù)組。那些麻煩的東西被lazy-arr封裝好了,生成器就是一行代碼。
是不是很優(yōu)雅?
來(lái)自:http://www.zcfy.cc/article/performancejs-introducing-lazy-arrays-in-javascript-3312.html
相關(guān)文章:
1. 告別AJAX實(shí)現(xiàn)無(wú)刷新提交表單2. XML入門的常見(jiàn)問(wèn)題(一)3. XML入門的常見(jiàn)問(wèn)題(四)4. CSS hack用法案例詳解5. CSS3實(shí)例分享之多重背景的實(shí)現(xiàn)(Multiple backgrounds)6. Vue+elementUI下拉框自定義顏色選擇器方式7. 詳解盒子端CSS動(dòng)畫性能提升8. 低版本IE正常運(yùn)行HTML5+CSS3網(wǎng)站的3種解決方案9. 使用css實(shí)現(xiàn)全兼容tooltip提示框10. css進(jìn)階學(xué)習(xí) 選擇符
