摘要:對于函數的柯里化應該不陌生,簡單來說技術是一種通過把多個參數填充到函數體中,實現將函數轉換為一個新的經過簡化的使之接受的參數更少函數的技術。
對于函數的柯里化(currying)應該不陌生,簡單來說 Currying 技術是一種通過把多個參數填充到函數體中,實現將函數轉換為一個新的經過簡化的(使之接受的參數更少)函數的技術。當發現正在調用同一個函數時,并且傳遞的參數絕大多數都是相同的,那么用一個Curry化的函數是一個很好的選擇.
下面利用閉包實現一個curry化的加法函數, 我們簡單理解一下 curry 化:
function add(x, y){ if(x && y) return x + y; if(!x && !y) throw Error("Cannot calculate"); return function(newx){ return x + newx; }; } add(3)(4); //7 add(3, 4); //7 var newAdd = add(5); newAdd(8); //13 var add2000 = add(2000); add2000(100); //2100
這樣做其實很類似 bind:
function add(a, b){ console.log(a+b); return a + b; } add(3, 4); //7 add.bind(null, 3)(4); //7 var newAdd = add.bind(null, 5); newAdd(8); //13 var add2000 = add.bind(null, 2000); add2000(100); //2100
同理也可以使用 call 和 apply, 因為他們可以實現 bind 的功能:
Function.prototype.bind = function(context){ var _this = this; var args = [].slice.call(arguments, 1); return function (){ innerArgs = [].slice.call(arguments); if(innerArgs && innerArgs.length > 0) args.push.apply(args, innerArgs); return _this.apply(context, args); } } add(3, 4); //7 add.bind(null, 3)(4); //7 var newAdd = add.bind(null, 5); newAdd(8); //13 var add2000 = add.bind(null, 2000); add2000(100); //2100
但是,如果看到了這個題:
實現一個函數sum,運算結果可以滿足如下預期結果:
sum(1,2,3); //6 sum(2,3)(2); //7 sum(1)(2)(3)(4); //10 sum(2)(4,1)(2); //9
還覺得簡單么?我們理一下思路。首先試想一下這個 sum 函數的結構:
function sum(){ return function(){ return function(){ //... } } }
這個函數返回的一定是個函數,但貌似需要寫無限個,這個不合理,我們修改一下:
function sum(){ function innerSum(){ //... return innerSum(); } return innerSum(); }
這樣一來每次調用就不需要定義無限個函數了。我們完善里面的代碼:
//sum(1,2,3); //6 //sum(2,3)(2); //7 //sum(1)(2)(3)(4); //10 //sum(2)(4,1)(2); //9 function sum(){ var cur = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); function innerSum(){ var next = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); cur += next; return innerSum; } return innerSum; }
這樣 sum 函數的柯里化過程就完成了,但是這個函數的返回的總是一個函數,這樣我們如何輸出數值呢?我們可以借助隱式類型轉換需要的 toString 函數實現:
function sum(){ var cur = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); function innerSum(){ var next = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); cur += next; return innerSum; } innerSum.toString = function(){ return cur; } return innerSum; } console.log(sum(1,2,3)); //6 console.log(sum(2,3)(2)); //7 console.log(sum(1)(2)(3)(4)); //10 console.log(sum(2)(4,1)(2)); //9
計算結果沒錯,我們還可以換作 valueOf 實現:
function sum(){ var cur = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); function innerSum(){ var next = [].slice.call(arguments).reduce(function(a,b){return a+b;},0); cur += next; return innerSum; } innerSum.valueOf = function(){ return cur; } return innerSum; } console.log(sum(1,2,3)); //6 console.log(sum(2,3)(2)); //7 console.log(sum(1)(2)(3)(4)); //10 console.log(sum(2)(4,1)(2)); //9
其實,如果同時存在 toString 和 valueOf 系統會先調用 toString, 然后調用valueOf,返回值自然是 valueOf 的返回值。這個很基礎,這里就不提了。
通用柯里化方法
通用的柯里化寫法其實比之前的 sum 函數要簡單許多
var currying = function(fn) { // 主要還是收集所有需要的參數到一個數組中,便于統一計算 var args = [].slice.call(arguments, 1); return function(){ var _args = args.concat([].slice.call(arguments)); return fn.apply(null, _args); } } var sum = function(){ var args = [].slice.call(arguments); return args.reduce(function(a, b) { return a + b; }); }; var sum10 = currying(sum, 10); console.log(sum10(20, 10)); // 40 console.log(sum10(10, 5)); // 25
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/107628.html
摘要:忍者秘籍一書中,對于柯里化的定義如下在一個函數中首先填充幾個參數然后再返回一個新函數的技術稱為柯里化。回到我們的題目本身,其實根據測試用例我們可以發現,函數的要求就是接受單一函數,例如但是與柯里化不同之處在于,柯里化返回的一個新函數。 歡迎大家再一次來到我的文章專欄:從面試題中我們能學到什么,各位同行小伙伴是否已經開始了悠閑的春節假期呢?在這里提前祝大家雞年大吉吧~哈哈,之前有人說...
摘要:函數柯里化在函數式編程中,函數是一等公民。函數柯里化的主要作用和特點就是參數復用提前返回和延遲執行。可能在實際應用場景中,很少使用函數柯里化的解決方案,但是了解認識函數柯里化對自身的提升還是有幫助的。 最近在整理面試資源的時候,發現一道有意思的題目,所以就記錄下來。 題目 如何實現 multi(2)(3)(4)=24? 首先來分析下這道題,實現一個 multi 函數并依次傳入參數執行,...
摘要:函數柯里化關于函數柯里化的問題最初是在忍者秘籍中講閉包的部分中看到的,相信很多同學見過這樣一道和柯里化有關的面試題實現一個函數,使得如下斷言能夠能夠通過簡單說就是實現一個求值函數,能夠將所有參數相加得出結果。方法返回一個表示該對象的字符串。 函數柯里化 ??關于函數柯里化的問題最初是在《JavaScript忍者秘籍》中講閉包的部分中看到的,相信很多同學見過這樣一道和柯里化有關的面試題:...
摘要:原題如下寫一個方法,當使用下面的語法調用時,能正常工作這道題要考察的,就是對函數柯里化的理解。當參數只有一個的時候,進行柯里化的處理。這其實就是函數柯里化的簡單應用。 showImg(https://segmentfault.com/img/bVbopGm?w=620&h=350); 前言 這是前端面試題系列的第 6 篇,你可能錯過了前面的篇章,可以在這里找到: ES6 中箭頭函數的...
閱讀 2955·2023-04-25 22:16
閱讀 2120·2021-10-11 11:11
閱讀 3254·2019-08-29 13:26
閱讀 600·2019-08-29 12:32
閱讀 3420·2019-08-26 11:49
閱讀 2998·2019-08-26 10:30
閱讀 1950·2019-08-23 17:59
閱讀 1514·2019-08-23 17:57