对Javascript柯里化currying的理解

1. 学习currying

对于currying,在《Javascript高级程序设计(第3版)》的604页第22.1.5节有一句言简意赅的解释:“它用于创建已经设置好了一个或多个参数的函数”。要更好的学习和理解currying,建议阅读以下几篇博文:
  • JS中的柯里化(currying) —— 张鑫旭
  • javascript的currying函数 —— 司徒正美
  • Javascript中currying的实现 —— Aaron

如果要我自己写,最多也就是对以上几篇的重复,所以理论部分不再赘述,下面讲讲我的理解。

2. 使用currying

市面上有很多currying的实现,实际上达成的效果都一致:我们有一个函数fn,通过currying(fn[, arg1][, arg2][, ...][, argn]),将fn包装为前n个参数固定的新函数,这里的n为currying中的arg数。

在看currying的时候,大家最爱用add函数的例子(参见1中建议阅读的几篇博文):

function add(x, y) {
    return x + y;
}

通过以下方式可以固定add的第一个参数,产生从addZero到addNine的函数(先忽略掉currying及其注释说明,看currying对add产生的效果,这里主要看for(var key in dict)循环里的注释):

function gener() {
    var currying = function(fn) {
        // fn 要进行柯里化的函数
        // args 固定下来的参数,可以多个
        var args = [].slice.call(arguments, 1);
        // 包装fn,里面的arguments是向包装后的fn传入的未固定参数,args已固定参数
        return function() {
            // 已经固化的参数args和新传入的参数arguments连接成新参数数组newArgs
            var newArgs = args.concat([].slice.call(arguments));
            // 包装原fn并返回,参数为newArgs,apply(null, [...])方便直接用数组参数newArgs调fn
            return fn.apply(null, newArgs);
        };
    };

    function add(a, b) {
        return a + b;
    }

    var dict = {
        addNine: 9, addEight: 8, addSeven: 7, addSix: 6, addFive: 5,
        addFour: 4, addThree: 3, addTwo:   2, addOne: 1, addZero: 0
    };
    for(var key in dict) {
        // 相当于执行(this是window):
        // this.addNine = cuurying(add, 9)
        // this.addEight = cuurying(add, 8)
        // ...
        // this.addZero = cuurying(add, 0)
        // 其中,addNine是固化add的第一个参数为9的函数,其他同理
        this[key] = currying(add, dict[key]);
    }

}

gener();

console.log(['addZero(1): ' , addZero(1)].join('') );
console.log(['addOne(1): '  , addOne(1)].join('')  );
console.log(['addTwo(1): '  , addTwo(1)].join('')  );
console.log(['addThree(1): ', addThree(1)].join(''));
console.log(['addFour(1): ' , addFour(1)].join('') );
console.log(['addFive(1): ' , addFive(1)].join('') );
console.log(['addSix(1): '  , addSix(1)].join('')  );
console.log(['addSeven(1): ', addSeven(1)].join(''));
console.log(['addEight(1): ', addEight(1)].join(''));
console.log(['addNine(1): ' , addNine(1)].join('') );

控制台输出:
对Javascript柯里化currying的理解_第1张图片
上面代码中使用的currying函数如下(注释写得不好,希望能帮助理解,这里将上面的currying函数提出来放这里,它是实现柯里化的关键):

var currying = function(fn) {
    // fn 要进行柯里化的函数
    // args 固定下来的参数,可以多个
    var args = [].slice.call(arguments, 1);
    // 包装fn,里面的arguments是向包装后的fn传入的未固定参数,args已固定参数
    return function() {
        // 已经固化的参数args和新传入的参数arguments连接成新参数数组newArgs
        var newArgs = args.concat([].slice.call(arguments));
        // 包装原fn并返回,参数为newArgs,apply(null, [...])方便直接用数组参数newArgs调fn
        return fn.apply(null, newArgs);
    };
};

说明都写在注释中了,如果理解困难,可以参考第1部分中的几篇博文。大家可能还不知道柯里化的作用,可以查看 张鑫旭的《JS中的柯里化(currying)》中的第二部分“柯里化有什么作用?”。

你可能感兴趣的:(Javascript,javascript,js,currying,柯里化,前端)