1. 程式人生 > >JavaScript中的柯里化(curry)

JavaScript中的柯里化(curry)

一、什麼是柯里化?

柯里化是一個轉換過程,把一個接受多個引數的函式,轉換成一個接受一個單一引數的函式,並且返回一個函式,返回的函式接受其餘的引數,並返回結果。

舉個例子:

// 無柯里化
var example1 = function (a, b, c) {  
// do something with a, b, and c
};

// 柯里化
var example2 = function(a) {
 return function (b) {
  return function (c) {    
    // do something with a, b, and c
  };
 };
};

二、柯里化的實現

  1. 首先將引數分割,將除了func之外的引數存進args
  2. 返回的函式接受新傳入的引數並與之前的引數合併,從而將所有的引數傳入函式中,並執行真正的函式
var curry = function(func){
    var args = [].slice.call(arguments,1);
    return function(){
        var newArgs = args.concat([].slice.call(arguments));
        return func.apply(this,newArgs);
    }
}

使用如下:

function
add(a, b) { return a + b; } var addCurry = curry(add,1,2);
addCurry(); //3 //或者 var addCurry = curry(add,1); addCurry(2); //3 //或者 var addCurry = curry(add); addCurry(1, 2) // 3

但是此時柯里化的函式只能被呼叫一次,不能實現addCurry(1)(2)的操作

改進版:

比如說add這個函式接受兩個引數,那麼針對柯里化之後的函式,若傳入的引數沒有到達兩個的話,就繼續呼叫curry,繼續接受引數。若引數到達2個了,就直接呼叫add函式。

var curry = function(func,args){
    var length = func.length;
    args = args||[];

    return function(){
        newArgs = args.concat([].slice.call(arguments));
        if(newArgs.length < length){
            return curry.call(this,func,newArgs);
        }else{
            return func.apply(this,newArgs);
        }
    }
}
var addCurry = curry(add);
addCurry(1,2) //3
addCurry(1)(2) //3

進階版:

但這一版柯里化函式仍然不能完全滿足要求,因為它只針對有特定引數個數的函式適用。
在前端面試中有一個關於柯里化的面試題:

實現一個add方法,使計算結果能夠滿足如下預期:
add(1)(2)(3) = 6
add(1, 2, 3)(4) = 10
add(1)(2)(3)(4)(5) = 15

我們之前寫的柯里化是不能滿足這個需求的,因為傳入的引數個數是不固定的。
其實這裡的需求是我們在柯里化的過程中既能返回一個函式繼續接受剩下的引數,又能就此輸出當前的一個結果。

這裡就需要使用函式的toString來完成。
當我們返回函式的時候,會呼叫函式的toString來完成隱式轉換,這樣輸出的就不是函式的字串形式而是我們定義的toString返回的值。這樣就既可以保持返回一個函式,又能夠得到一個特定的值。

function add(){
    var args = [].slice.call(arguments);
    var fn = function(){
        var newArgs = args.concat([].slice.call(arguments));
        return add.apply(null,newArgs);
    } 
    fn.toString = function(){
        return args.reduce(function(a, b) {
            return a + b;
        })
    }
    return fn ;
}
add(1)(2,3) //f 6
add(1)(2,3).toString() //6
add(1)(2)(3)(4)(5).toString() //15

這樣這個函式可以接受任意個數的引數,被呼叫任意次。
呼叫過程:

  • add(1),返回:
function(){
        var newArgs = [1].concat([].slice.call(arguments));
        return add.apply(null,newArgs);
    } 
  • add(1)(2,3),相當於:
(function(){
        var newArgs = args.concat([].slice.call(arguments));
        return add.apply(null,newArgs);
    })(2,3);

此時新引數newArgs為[1,2,3],同時再次呼叫add,返回函式:

function(){
        var newArgs = [1,2,3].concat([].slice.call(arguments));
        return add.apply(null,newArgs);
    } 

並且此函式的值為toString的結果即6,因此可以輸出6。
其實就是每次都更新當前的引數,重新呼叫一下add函式,並計算當前為止的結果。

其實這個函式沒有什麼通用性,通常用於封裝特定的函式。還是前面兩版柯里化函式比較通用。

相關推薦

JavaScriptcurry

一、什麼是柯里化? 柯里化是一個轉換過程,把一個接受多個引數的函式,轉換成一個接受一個單一引數的函式,並且返回一個函式,返回的函式接受其餘的引數,並返回結果。 舉個例子: // 無柯里化 var example1 = function (a, b, c

scala高階語法之curring和 隱式轉換implicit

柯里化(curring)和 隱式轉換(implicit) 柯里化(curring) scala 中 curring 是將一個正常的方法轉換為科裡化的一個過程 把一個引數列表中的多個引數轉換為多個列表 如:①→② ① def m1(a:Int,b:Int)=a+b

函式currying

currying的好處 Little pieces can be configured and reused with ease, without clutter. Functions are used throughout. 例子1 let

淺談 Swift Currying

       在 Swifter中,第一章 就是 講解 柯里化。這本書 真的是非常的不錯,值得一看,同時,正如作者王巍所說,國內的 大量的流水線書籍真的沒必要買。如果 你希望入門,去這裡,如果 你想提高,我非常推薦這本書。當然 你也可以在這裡找到它的內容。       

JavaScript函數的currying

HR rip 求解 type targe font 可能 上下 實例 轉載請註明出處:http://www.cnblogs.com/shamoyuu/p/currying.html 什麽是js函數的currying /柯裏化? 說到js的柯裏化,相信很多朋友都會頭

javascript的DOM介紹

item 檢測 turn 及其 篩選 層次 proto nbsp log 一、基礎知識點 1、DOM是文檔對象模型,是針對HTML和XML文檔的一個API(應用程序接口) 2、DOM描繪了一個層次化的節點數,允許開發人員進行添加,移除個修改等操作 3、IE瀏覽器中所有的DO

[JavaScript]JavaScript的函數2

ron 總結 href 尋找 tro http cal con 如果 承接上一篇博文的總結,這篇博文是利用代碼+畫圖的形式,梳理一下對於函數作用域和閉包的理解。 函數中的作用域 在 JavaScript 中, 對象和函數同樣也是變量。 在 JavaScript 中, 作用

淺析JavaScriptFunction對象

中一 {} .proto 及其 pro type屬性 tor 下一個 所有   一、Function對象及其原型對象   Function對象是js中一個非常重要的對象,所有通過function關鍵字聲明的函數,本質上都是由Function這個特殊的構造器對象創建出來的,也

js的函式(curry)和函式組合

原文: Eric Elliott - Curry and Function Composition 譯文: curry和函式組合 提醒: 本文略長,慎重閱讀 之前看到有文章說柯里化函式,大致看了下,就是高階函式,只是名字聽起來比較高大上一點,今天逛medium又發現了這個,看

JavaScript的for in 1

for (variable in object) statement; 在執行for/in語句過程中,JavaScript直譯器會首先計算object表示式。如果表示式為null或undefined,JavaScript直譯器將會跳過迴圈並執行後續程式碼。如果表示

kaggle的視覺:House Prices

kaggle中預測的get started專案,原文連結。 看原文可以入門特徵工程,這裡主要說視覺化部分,用到matplotlib和seaborn。 導庫增加 import seaborn as sns from scipy.stats import

資料預處理歸一Normalization與損失函式正則Regularization解惑

背景:資料探勘/機器學習中的術語較多,而且我的知識有限。之前一直疑惑正則這個概念。所以寫了篇博文梳理下 摘要:   1.正則化(Regularization)     1.1 正則化的目的      1.2 結構風險最小化(SRM)理論     1.3 L1範數

javascript的事件Event— 事件流

 一、Event基本資訊1、事件流:描述的是從頁面中接受事件的順序       IE的事件流是事件冒泡流,Netscape的事件流是事件捕獲流。 2、事件冒泡      IE的事件流叫做事件冒泡(event bubbing),即事件開始時由具體的元素接受,然後逐級向上傳播

談談 JavaScript 的 宣告提前hoisting

有許多同學知道js在執行的時候,是從上到下,從左到右,一行一行執行的,但是不知道在這之前還要做一些事情,js程式在正式執行之前,會將所有var 宣告的變數和function宣告的函式,預讀到所在作用域的頂部,但是對var 宣告只是將宣告提前,賦值仍然保留在原位置

簡析JavaScript的Function型別——函式名是指標

浪費了“黃金五年”的Java程式設計師,還有救嗎? >>>   

簡析JavaScript的Function型別——函式宣告與函式表示式的區別

開發十年,就只剩下這套架構體系了! >>>   

簡析JavaScript的Function型別——作為值的函式

開發十年,就只剩下這套架構體系了! >>>   

簡析JavaScript的Function型別——函式的內部屬性

開發十年,就只剩下這套架構體系了! >>>   

簡析JavaScript的Function型別——設定函式的作用域

開發十年,就只剩下這套架構體系了! >>>   

漫談JavaScript的作用域scope

什麼是作用域 程式的執行,離不開作用域,也必須在作用域中才能將程式碼正確的執行。 所以作用域到底是什麼,通俗的說,可以這樣理解:作用域就是定義變數的位置,是變數和函式的可訪問範圍,控制著變數和函式的可見性和生命週期。 而JavaScript中的作用域,在ES6之前和ES6之後,有兩種不同的情況。 ES6之前,