摘要:最直接的方式當然是遍歷數組并累加得到結果,也可以使用數組的方法實現,如下結合第四步,替換中的返回值即可將其進行簡化,得到最終結果當然,采用這種實現方式,對于形如的調用方式也是沒有問題的。
第一步:實現級聯談談 JavaScript 中形如 add(1)(2)(3)(4) = 10 這種累加器方法的實現過程和思路
若是想要實現 fn()() 這種調用方式的函數,則在 fn 函數體內一定也會返回一個函數,如下:
function fn(){ return function(){ } }
再進一步,若是想要實現 fn()()()... 不定次數的調用,則意味著每一層的返回值均為一個函數,這就需要使用類似遞歸的方式去實現:
function fn(){ var _fn = function(){ return _fn; } return _fn; }第二步:實現返回值
如果每一層的返回值均為函數,那么如何返回累加結果呢?也就是說,在函數調用的最后一層,這個返回值應該是一個值而非函數。這里則需要使用 valueOf 這一方法,例子如下:
function fn1(){ } console.log(fn1); // function ... function fn2(){ } fn2.valueOf = function(){ return 1; } console.log(fn2); // function 1
注意,fn2 在控制臺的輸出結果為 function 1,但其數值型隱式轉換的結果為 1,也就是說 console.log(+fn2) 或是 var num = fn2 + 1 是可以正常地作為數值型進行計算的。而 fn2() 的方式仍然可以將其作為函數運算。
因而,我們只要給 _fn 添加 valueOf 方法就可以實現在不定次調用之后,得到一個「值」而非「函數」,如下:
function fn(){ var _fn = function(){ return _fn; } _fn.valueOf = function(){ return 12345; } return _fn; }
第三步:獲得傳入的參數這里也可以使用添加 toString() 的方式實現這一功能,與 valueOf() 做法一致。
這一步相對簡單,使用內置對象 arguments 即可實現對函數中所傳入的參數的獲取,如下:
function foo(){ console.log(arguments); } foo(1,2,3);
注意,這里的 arguments 不是數組,而是對象:
{ 0 : 1, 1 : 2, 2 : 3, callee : function foo(), length : 3, Symbol(Symbol.iterator) : function values(), __proto__ : Object, }
若要將其轉換為數組,可以使用如下方式:
var arr = [].slice.call(arguments); // 或是 var arr = Array.prototype.slice.call(arguments);
第四步:實現參數保存若一個對象含有 length 屬性,則可以通過這種方式轉換為數組形式
add(1)(2)(3)... 累加器是在最后一次調用后返回之前所有參數的累加和。也就是說我們需要有一個地方可以保存先前的值或是計算結果。
在之前的代碼框架下,顯然不能將其保存在內層的 _fn 中。因為每層調用都相當于又一次的 _fn() 執行,在其中定義的變量會被覆蓋。
使用全局變量當然是一種方式,但是這樣會污染全局空間,不是最佳方案。
考慮到對 fn()()()... 的調用實際返回的是內層的 _fn,意味著 fn 的局部變量其實也相當于 _fn 的全局變量。因而可以將保存先前參數的職責交給 fn 中的一個變量,代碼如下:
function fn(){ var numList = []; var _fn = function(){ // 這里測試思路是否可行 numList.push(1); console.log(numList); return _fn; } _fn.valueOf = function(){ return 12345; } return _fn; } console.log(fn()()()); // [1, 1] // 注意這里雖然調用三次,但實際只執行了兩次 push(1),第一次調用沒有執行內層的 _fn(),而只是返回了它。
結合第三步,我們可以通過 push() 或是 concat() 的方式將每一次的參數組合起來,如下:
function fn(){ var numList = [].slice.call(arguments); var _fn = function(){ // 注意這里的 arguments 是傳入 _fn 的參數 var innerArguments = [].slice.call(arguments); numList = numList.concat(innerArguments); console.log(numList); return _fn; } _fn.valueOf = function(){ return 12345; } return _fn; } console.log(fn(1)(2)(3)); // [1, 2, 3]
當然,這里也可以使用 push() 的方式,將每一次的參數推入數組。
第五步:求和計算這一步還有另一種思路:用每一次的求和代替參數數組的合并。
既然已經得到了全部的參數集合,對其進行求和就比較簡單了。最直接的方式當然是遍歷數組并累加得到結果,也可以使用數組的 reduce 方法實現,如下:
var arr = [1, 2, 3]; var sum = arr.reduce(function(num1, num2){ return num1 + num2; }); console.log(sum); // 6
結合第四步,替換 valueOf 中的返回值即可:
function fn(){ var numList = [].slice.call(arguments); var _fn = function(){ var innerArguments = [].slice.call(arguments); numList = numList.concat(innerArguments); return _fn; } _fn.valueOf = function(){ return numList.reduce(function(num1, num2){ return num1 + num2; }); } return _fn; } console.log(fn(1)(2)(3));
將其進行簡化,得到最終結果:
function fn(){ var numList = [].slice.call(arguments); var _fn = function(){ numList = numList.concat([].slice.call(arguments)); return _fn; } _fn.valueOf = function(){ return numList.reduce(function(i, j){return i+j;}); } return _fn; }
參考當然,采用這種實現方式,對于形如 fn(1, 2, 3)(4)(5, 6, 7) 的調用方式也是沒有問題的。
前端基礎進階(八):深入詳解函數的柯里化 - 簡書
JS中的call()和apply()方法 - ITeye
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81858.html
摘要:忍者秘籍一書中,對于柯里化的定義如下在一個函數中首先填充幾個參數然后再返回一個新函數的技術稱為柯里化。回到我們的題目本身,其實根據測試用例我們可以發現,函數的要求就是接受單一函數,例如但是與柯里化不同之處在于,柯里化返回的一個新函數。 歡迎大家再一次來到我的文章專欄:從面試題中我們能學到什么,各位同行小伙伴是否已經開始了悠閑的春節假期呢?在這里提前祝大家雞年大吉吧~哈哈,之前有人說...
摘要:原題如下寫一個方法,當使用下面的語法調用時,能正常工作這道題要考察的,就是對函數柯里化的理解。當參數只有一個的時候,進行柯里化的處理。這其實就是函數柯里化的簡單應用。 showImg(https://segmentfault.com/img/bVbopGm?w=620&h=350); 前言 這是前端面試題系列的第 6 篇,你可能錯過了前面的篇章,可以在這里找到: ES6 中箭頭函數的...
摘要:里也有柯里化的實現,只是平時沒有在意。如果函數柯里化后雖然生搬硬套,不過現實業務也會有類似場景。 柯里化 先解釋下什么是 柯里化 在計算機科學中,柯里化(英語:Currying),又譯為卡瑞化或加里化,是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,并且返回接受余下的參數而且返回結果的新函數的技術。 js 里也有柯里化的實現,只是平時沒有在意。先把原文簡介貼...
摘要:函數式編程的定義函數是一段可以通過其名稱被調用的代碼。純函數大多數函數式編程的好處來自于編寫純函數,純函數是對給定的輸入返回相同的輸出的函數,并且純函數不應依賴任何外部變量,也不應改變任何外部變量。 一個持續更新的github筆記,鏈接地址:Front-End-Basics,可以watch,也可以star。 此篇文章的地址:JavaScript函數式編程入門經典 正文開始 什么是函...
閱讀 3492·2023-04-26 02:44
閱讀 1629·2021-11-25 09:43
閱讀 1521·2021-11-08 13:27
閱讀 1885·2021-09-09 09:33
閱讀 903·2019-08-30 15:53
閱讀 1765·2019-08-30 15:53
閱讀 2778·2019-08-30 15:53
閱讀 3110·2019-08-30 15:44