柯里化(currying)與部分應(yīng)用(partial application) / 優(yōu)化嵌套的條件語句 / 運(yùn)用存儲(chǔ)加速遞歸

JavaScript的那些奇技淫巧

馬躍Marico4 天前

一. No1.柯里化(currying)與部分應(yīng)用(partial application)
柯里化(currying)
柯里化是使一個(gè)函數(shù)
f: X * Y -> R
轉(zhuǎn)變?yōu)?br> f’: X -> (Y -> R)
與用兩個(gè)參數(shù)調(diào)用f不同,我們用一個(gè)參數(shù)運(yùn)行f’。返回的結(jié)果是一個(gè)函數(shù),然后用第二個(gè)參數(shù)調(diào)用此函數(shù),得到結(jié)果。
如此,如果未柯里化的函數(shù)f這樣調(diào)用
f(3,5)
柯里化后的函數(shù)f’是這樣調(diào)用的
f(3)(5)
比如: 未柯里化的函數(shù)add()
function add(x, y) { return x + y;}add(3, 5); // returns 8

柯里化后的add()
function addC(x) { return function (y) { return x + y; }}addC(3)(5); // returns 8

柯里化的規(guī)則
柯里化將一個(gè)二元函數(shù),轉(zhuǎn)變?yōu)橐辉瘮?shù),這個(gè)函數(shù)將返回另一個(gè)一元函數(shù)。
curry: (X × Y → R) → (X → (Y → R))
Javascript Code:
function curry(f) { return function(x) { return function(y) { return f(x, y); } }}

部分應(yīng)用(partial application)
部分應(yīng)用將一個(gè)函數(shù)
f: X * Y -> R
的第一個(gè)參數(shù)固定而產(chǎn)生一個(gè)新的函數(shù)
f`: Y -> R
f’與f不同,只需要填寫第二個(gè)參數(shù),這也是f’比f少一個(gè)參數(shù)的原因。
比如:將函數(shù)add的第一個(gè)參數(shù)綁定為5來產(chǎn)生函數(shù)plus5。
function plus5(y) { return 5 + y;}plus5(3); // returns 8

部分應(yīng)用的規(guī)則
部分應(yīng)用使用一個(gè)二元函數(shù)和一個(gè)值產(chǎn)生了一個(gè)一元函數(shù)。
partApply : ((X × Y → R) × X) → (Y → R)
Javascript Code:
function partApply(f, x) { return function(y) { return f(x, y); }}

No2.優(yōu)化嵌套的條件語句
我們?cè)鯓觼硖岣吆蛢?yōu)化javascript里嵌套的if語句呢?
if (color) { if (color === 'black') { printBlackBackground(); } else if (color === 'red') { printRedBackground(); } else if (color === 'blue') { printBlueBackground(); } else if (color === 'green') { printGreenBackground(); } else { printYellowBackground(); }}

一種方法來提高嵌套的if語句是用switch語句。雖然它不那么啰嗦而且排列整齊,但是并不建議使用它,因?yàn)檫@對(duì)于調(diào)試錯(cuò)誤很困難。這告訴你為什么。
switch(color) { case 'black': printBlackBackground(); break; case 'red': printRedBackground(); break; case 'blue': printBlueBackground(); break; case 'green': printGreenBackground(); break; default: printYellowBackground();}

如果可以重構(gòu)的話,我們可以試著簡(jiǎn)化函數(shù)。比如不需要為每個(gè)顏色寫一個(gè)函數(shù),而是將顏色作為函數(shù)的參數(shù)。
function printBackground(color) { if (!color || typeof color !== 'string') { return; }}

但是如果不能重構(gòu)的話,我們必須避免過多的條件檢查,避免過多使用switch。我們必須考慮最有效率的方法,使用object。
let colorObj = { 'black': printBlackBackground, 'red': printRedBackground, 'blue': printBlueBackground, 'green': printGreenBackground, 'yellow': printYellowBackground};if (color in colorObj) { colorObjcolor;}

No3.運(yùn)用存儲(chǔ)加速遞歸
大家對(duì)斐波那契(Fibonacci)數(shù)列都很熟悉。我們可以再20秒內(nèi)寫出下面這樣一個(gè)方法。
var fibonacci = function(n){ return n < 2 ? n : fibonacci(n-1) + fibonacci(n-2);}

它可以運(yùn)行,但并不高效。它做了太多重復(fù)的運(yùn)算,我們可以通過存儲(chǔ)這些運(yùn)算結(jié)果來使其加速。
var fibonacci = (function() { var cache = [0, 1]; // cache the value at the n index return function(n) { if (cache[n] === undefined) { for (var i = cache.length; i <= n; ++i) { cache[i] = cache[i-1] + cache[i-2]; } } return cache[n]; }})()

我們也可以定義一個(gè)高階函數(shù),它接收一個(gè)方法作為參數(shù),返回一個(gè)該方法運(yùn)用存儲(chǔ)后的新方法。
var memoize = function(func){ var cache = {}; return function(){ var key = Array.prototype.slice.call(arguments).toString(); return key in cache ? cache[key] : (cache[key] = func.apply(this,arguments)); }}fibonacci = memoize(fibonacci);

ES6版本的memoize函數(shù)如下:
var memoize = function(func){ const cache = {}; return (...args) => { const key = [...args].toString(); return key in cache ? cache[key] : (cache[key] = func(...args)); }}fibonacci = memoize(fibonacci);

我們可以將memoize()用在很多其他地方

  • GCD(最大公約數(shù))
    var gcd = memoize(function(a,b){ var t; if (a < b) t=b, b=a, a=t; while(b != 0) t=b, b = a%b, a=t; return a;})gcd(27,183); //=> 3

  • 階乘運(yùn)算
    var factorial = memoize(function(n) { return (n <= 1) ? 1 : n * factorial(n-1);})factorial(5); //=> 120

Original:[Js Tips - A JavaScript tip per day!*
") 0px 2px / cover;">*
](Js Tips - A JavaScript tip per day!*
") 0px 2px / cover;">*
)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.函數(shù)參數(shù)的默認(rèn)值 (1).基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值,只能采用變通的方法。
    趙然228閱讀 829評(píng)論 0 0
  • 原文鏈接 Haskell和scala都支持函數(shù)的柯里化,JavaScript函數(shù)的柯里化還與JavaScript的...
    dreamapple閱讀 2,656評(píng)論 0 24
  • SwiftDay011.MySwiftimport UIKitprintln("Hello Swift!")var...
    smile麗語閱讀 4,080評(píng)論 0 6
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,890評(píng)論 0 33
  • 今天,是不平靜的一天,沒有遇到意外,也沒有身體不舒服,是內(nèi)心好久以來沒有這樣像過電影一樣回想起往日的種種場(chǎng)景,...
    佳貝健康閱讀 163評(píng)論 0 1

友情鏈接更多精彩內(nèi)容