Javascript中的函数柯里化详解

195 阅读2分钟

柯里化

背景

  • 前不久面试某大厂被问到关于函数柯里化的问题,才疏学浅的我一脸懵逼,面试官以为自己没描述清楚,刻意把整个单词 Currying 拼了一遍,然后我该不知道的还是不知道。之前好像是在哪里见过,但是也没仔细去研究过,今天就来好好学习一番。

定义

  • 先看下什么是柯里化,维基百科上的解释如下,其实就是把接受的多参数转为接受单一参数的一种技术。

计算机科学中,柯里化(英语:Currying),又译为卡瑞化加里化,是把接受多个参数函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术

优点

  1. 参数复用
  2. 提前返回 – 返回接受余下的参数且返回结果的新函数
  3. 延迟执行 – 返回新函数,等待执行

实例

  • 普通函数
function add(x,y) {
    return x + y;
}
add(1,2) //3
  • 乞丐版柯里化写法
var add = function(x) {
    return function(y) {
      return x + y;
    }
};
add(1)(2) //3
  • 上面的实现参数是固定的,只能支持两个参数,如果想实现任意参数呢?如下:
  • 通用版
function add() {
    // 第一次执行时用来存储所有的参数
    var args = [].slice.call(arguments);

    // 利用闭包的特性保存args并收集所有的参数值
    var adder = function () {
        var _adder = function() {
            [].push.apply(args, [].slice.call(arguments));
            return _adder;
        };

        // 利用隐式转换的特性,当最后执行时进行隐式转换,并计算最终的值然后返回
        _adder.toString = function () {
        	// 使用reduce来实现求和
            return args.reduce(function (a, b) {
                return a + b;
            });
        }
        return _adder;
    }

    return adder.apply(null, [].slice.call(arguments));
}

// 输出结果,可自由组合的参数
console.log(add(1, 2, 3, 4, 5));  // 15
console.log(add(1, 2, 3, 4)(5));  // 15
console.log(add(1)(2)(3)(4)(5));  // 15
  • 高阶版-ES6骚写法
const currying = (fn, ...args) =>
    args.length < fn.length
        //参数长度不足时,重新柯里化该函数,等待接受新参数
        ? (...arguments) => currying(fn, ...args, ...arguments)
        //参数长度满足时,执行函数
        : fn(...args);
function sumFn(a, b, c) {
    return a + b + c;
}

var sum = currying(sumFn);

console.log(sum(2)(3)(5));//10
console.log(sum(2, 3, 5));//10
console.log(sum(2)(3, 5));//10
console.log(sum(2, 3)(5));//10
  • 实现bind函数
function mybind(fn) {
    return function() {
        return fn.apply(this, arguments);
    }
}

总结

  • 柯里化的主要好处是参数复用,提前返回 ,延迟执行,还是需要熟练掌握,在面试中属于高频知识点。

参考