Javascript中currying的實現

來源:互聯網
上載者:User

Currying好像是函數式語言都有的一個特性,比如Perl,Python,Javascript。

那麼到底什麼是Currying,我是在學習Closure時無意中接觸到這個定義的,覺得很是有趣。

先看看 Wiki 中的定義:

Currying is the technique of transforming a function that takes multiple arguments 

in such a way that it can be called as a chain of functions each with a single argument.

大概的意思就是說,將擁有多個參數的函數Currying化為擁有單一參數的函數形式。

下面舉一個簡單的例子說明Javascript中的Currying實現,一個簡單的求和函數:

 

function add(x, y) {
    return x + y;
}
console.log('add(2, 3) == ' + add(2, 3));

 

對其進行Currying,及調用方法:

function curry_add(x) {
    return function(y) {
        return x + y;
    }
}
console.log('curry_add(2)(3) == ' + curry_add(2)(3));

 

注意,curry_add(2) 返回的是函數。

 

我們還可以定義一個通用的 curry 函數:

 

function curry(fn) {
    var args = [];
    for (var i = 1; i < arguments.length; i++) {
        args.push(arguments[i]);
    }
    return function() {
        for (var i 

= 0; i < arguments.length; i++) {
            args.push(arguments[i]);
        }
        return fn.apply(window, args);
    }
}這個函數至少接收一個參數(需要curry的函數),對於前面的 add 函數,我們可以這樣來調用:console.log('curry(add)(2, 3) == ' + curry(add)(2, 3));
console.log('curry(add, 2)(3) == ' + curry(add, 2)(3));
console.log('curry(add, 2, 3)() == ' + curry(add, 2, 3)());

因為 curry(add, 2) 或 curry(add) 返回的還是函數,所以我們還可以對其進行Currying,如下代碼:

 

console.log('curry(curry(add), 2)(3) == ' + curry(curry(add), 2)(3));
console.log('curry(curry(add, 2), 3)() ==' + curry(curry(add, 2), 3)());

 

運行時:

代碼下載

 

[update_2009-2-17]

按照 @winter-cn 的提示,我來到另外一篇討論Currying的 文章 ,發現那裡的做法是寫一個可以 Chain 的Currying,

另外我還發現了一個我以前不知道的特性,add.length 返回的是函數形式參數的個數,比如這個例子中的 add.length == 2

這就好辦了,我們可以根據傳遞進來的參數的多少來判斷是否返回執行結果或者是返回函數。

我大概的想法是要用到遞迴,來看看我的實現:

 

function curry2(fn) {
    var args = [];
    for 

(var i = 1; i < arguments.length; i++) {
        args.push(arguments[i]);
    }
    return function() {
        for (var i = 0; i < arguments.length; i++) {
            args.push(arguments[i]);
        }
        if (args.length >= fn.length) {
            return fn.apply(window, args);
        }
        else {
            return curry2.apply(window, [fn].concat(args));
        }
    }
}
console.log('curry2(add)(2, 3) == ' + curry2(add)(2, 3));
console.log('curry2(add)(2)(3) == ' + curry2(add)(2)(3));

 

當然這樣的Currying技術,只能用在有明確形式參數的函數中,如果在add函數中使用arguments來捕獲參數,則這種Currying是行不通的。

上面的add可能不是很明顯,來看看擁有 4 個參數的add2函數,以及使用Currying技術:

 

function add2(x, y, z, k) {
    return x + y + z + k;
}
console.log('curry2(add2)(1, 2, 3, 4) == ' + curry2(add2)(1, 2, 3, 4));
console.log('curry2(add2)(1, 2, 3)(4) == ' + curry2(add2)(1, 2, 3)(4));
console.log('curry2(add2)(1, 2)(3, 4) == ' + curry2(add2)(1, 2)(3, 4));
console.log('curry2(add2)(1)(2, 3, 4) == ' + curry2(add2)(1)(2, 3, 4));
console.log('curry2(add2)(1)(2)(3, 4) == ' + curry2(add2)(1)(2)(3, 4));
console.log('curry2(add2)(1)(2)(3)(4) == ' + curry2(add2)(1)(2)(3)(4));

 

 

更新的代碼下載

 

附:John Resig在Pro Javascript一書中關於Currying的實現代碼:

 

// A function that generators a new function for adding numbers
function addGenerator( num ) {

    // Return a simple function for adding two numbers
    // with the first number borrowed from the generator
    return function( toAdd ) {
        return num + toAdd
    };

}

// addFive now contains a function that takes one argument,
// adds five to it, and returns the resulting number
var addFive = addGenerator( 5 );

// We can see here that the result of the addFive function is 9,
// when passed an argument of 4
alert( addFive( 4 ) == 9 );

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.