• Javascript中currying的实现


    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(23));

     

    对其进行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)(23));
    console.log(
    'curry(add, 2)(3) == ' + curry(add, 2)(3));
    console.log(
    'curry(add, 2, 3)() == ' + curry(add, 23)());


    因为 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)(23));
    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)(1234));
    console.log(
    'curry2(add2)(1, 2, 3)(4) == ' + curry2(add2)(123)(4));
    console.log(
    'curry2(add2)(1, 2)(3, 4) == ' + curry2(add2)(12)(34));
    console.log(
    'curry2(add2)(1)(2, 3, 4) == ' + curry2(add2)(1)(234));
    console.log(
    'curry2(add2)(1)(2)(3, 4) == ' + curry2(add2)(1)(2)(34));
    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 );

    复制代码
  • 相关阅读:
    人生,别认输,因为没人希望你赢
    一张图看懂开源许可协议,开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
    Android Studio 出现 Gradle's dependency cache may be corrupt 解决方案
    清华梦的粉碎——转自王垠
    label smooth
    <现代C++实战30讲>笔记 01 | 堆、栈、RAII:C++里该如何管理资源?
    h5转pb的两个坑
    opencv库的像素x,y,width,height,col,row的对应关系
    detect 导图
    keras多gpu训练
  • 原文地址:https://www.cnblogs.com/aaronjs/p/2570783.html
Copyright © 2020-2023  润新知