最終效果:
var greet = function(greeting, name) { return greeting + ' ' + name; }; var sayHelloTo = _.partial(greet, 'hello'); sayHelloTo('fred'); // => 'hello fred'
來自:http://lodashjs.com/docs/#_partialfunc-partials
除非你已經使用過其他的函數式編程,不然你可能對下面這兩個概念很陌生:“偏函數應用”和“函數柯里化“。
偏函數應用,英文是partial application,也可以譯作“局部應用”、“部分應用”、“偏應用” 函數柯里化,英文是currying,也可以譯作“局部套用”、“加里化”、“卡瑞化”
話雖如此,但是假如你一旦理解了這兩個概念,你就完全可以在自己的代碼里使用他們。
Functions
即使你已經很熟悉JavaScript的function, 知道function可以作為返回值,可以作為參數。
但是我還是推薦你讀一下這個第一部分。如果不需要,也可以跳過,直接看局部應用的章節。
我們首先看一個非常基礎的例子:
function add(a, b) { return a + b; } add(1, 2); // 3 add(1, 3); // 4 add(1, 10); // 11 add(1, 9000); // 9001
盡管上面的例子是非常的簡單,但是還是演示出了我們反復調用一個function的場景,並且每次傳入的第一個參數都是相同的,在上面的代碼里就是數字1
Functions返回Functions
我們也可以創建一個叫做makeAdder的function,這個function會返回另一個可以傳入參數的function。(像這種可以用來創建其他function或object的function,一般會叫做工廠 - factories)
返回的函數,如果往里面傳入參數調用,可以把傳入的參數值和原來設的參數值,返回相加的結果。
// More general function. function add(a, b) { return a + b; } add(1, 2); // 3 add(10, 3); // 13 // More specific function generator. function makeAdder(a) { return function(b) { return a + b; }; } // More specific functions. var addOne = makeAdder(1); addOne(2); // 3 addOne(3); // 4 var addTen = makeAdder(10); addTen(2); // 12 addTen(3); // 13
上面的代碼之所以可行,是因為JavaScript支持閉包的功能,由於閉包的存在,使得function可以訪問到這個function外部的變量,甚至在調用這個function時的作用域的外層。
除此之外,在JavaScript里面,function是一等公民。正因為如此,function可以接受function作為參數,也可以返回function.
閉包和函數這個一等公名經常一起配合着工作:使得返回的function可以繼續使用傳入的參數。
上面的代碼給我們提供了一些方便,我們可以不再使用add(1, 2),而直接使用addOne(2),但是實現這個並不是不需要付出代價的。
首先,實際做加法的邏輯在上面兩個例子的代碼中還是重復的,這樣還是會有些問題。
其次,對每個類似於上面的加法場景,用這種方式去獨立除不同的邏輯,我們將需要手工創建makeSomething的工廠function。
Functions接受Functions
下面的邏輯步驟是創建一個更普遍的工廠function,不僅接受一個要綁定的參數,也會接受一個function,這個function里面包含了所有的核心邏輯。(傳入到其他function的function,一般被成為回調函數-callbacks)
用這種方式,一個單獨的工廠function能夠被用來創建function綁定。
注意,原始的function被沒有被更新,並且他們的行為也不會改變。他們很容易被調用。
// Relatively flexible, more specific function generator. function bindFirstArg(fn, a) { return function(b) { return fn(a, b); }; } // More general functions. function add(a, b) { return a + b; } add(1, 2); // 3 function multiply(a, b) { return a * b; } multiply(10, 2); // 20 // More specific functions. var addOne = bindFirstArg(add, 1); addOne(2); // 3 addOne(3); // 4 addOne(10); // 11 addOne(9000); // 9001 var multiplyByTen = bindFirstArg(multiply, 10); multiplyByTen(2); // 20 multiplyByTen(3); // 30 multiplyByTen(10); // 100 multiplyByTen(9000); // 90000
上面這段代碼,亮點不在於它可以將某個參數綁定到任意的function,並且這個參數作為綁定的function的第一個參數,它還能將方法綁定它自己身上作為第一個參數,因此創建了一個可綁定的function
想想這種情況:假如bindFirstArg能夠將第一個參數綁定到一個function,但是這個function可以接受兩個參數,比如傳進去1和10,1用來加,10用來乘。
bindFirstArg可以接受兩個2參數,假如第一個參數是它自己,也就是bindFirstArg可以用來綁定它自己。
看下面的例子:
// More specific function generator. var makeAdder = bindFirstArg(bindFirstArg, add); // More specific functions. var addOne = makeAdder(1); addOne(2); // 3 addOne(3); // 4 var addTen = makeAdder(10); addTen(2); // 12 addTen(3); // 13