记录柯里化

182 阅读2分钟

记录科里化,检验自己的学习程度;

科里化定义:在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的。

--引用自百度百科

add(1)(2)(3)(4) = 10; 实现add函数

  • 参数长度一定(类似上边的参数长度为 4);
let sum = (a,b,c,d)=>a+b+c+d;
function curry(sum){
    let len = sum.length;  //  参数的长度
    let opts = [];
    // 利用闭包 收集参数 当长度 == len 的时候
    // 调用 sum
    return function next(...arg){ // 收集参数
        opts = opts.concat(arg);
        if(opts.length < len){
            return next;
        } else {
            return sum.apply(null,opts);
        }
    }
};
//  测试一下
let func = curry(sum);
console.log(func(1)(2)(3)(4));  // 10
console.log(func(1,2)(3)(4));   // 10

用到的知识点:闭包 迭代 我理解的 闭包:一种保存变量的机制 迭代的话 一定要注意边界

  • 参数长度不定,以()为边界 类似 add(1)(2)(3)(4)();

来实现

function curry2(fn) {
    let opts =[];
    return function next(...args) {
        opts = opts.concat(args)
        // 和上边的只是边界条件不同
        if(args.length){
            return next
        } else {
            return fn.apply(null,opts);
        }
    }
};
let add2 = function () {
    return [...arguments].reduce((prev,cur)=>prev+cur);
};
let func2 = curry2(add2);
console.log(func2(1)(2)(3)(4)());   // 10
console.log(func2(1)(2,3)(4)());    //10
  • 不定边界 类似 add(1)(2)(3)(4)...(101)...

这个边界改怎么确定,是个最难的问题,先来看实现

function curry3(fn) {
    let opts = [];
    console.log('opts');
    function next(...args) { //  next仅仅用来收集参数
        opts = opts .concat(args);
        return next
    }
    //  字符类型
    next.valueOf = function () {
        return fn.apply(null, opts);
    }
    // 数值类型
    next.toString = function () {
        return fn.apply(null, opts);
    }
    return next;
};
let add3 = function () {
    return [...arguments].reduce((prev,cur)=>prev+cur);
};
let func3 = curry3(add3);
func3(1)(2)(3)(4);
console.log(func3(1)(2)(3)(4));   // 10
console.log(func3(1)(2,3)(4));    //10

重写了next的 toString 和 valueOf 函数,当调用这两个函数的时候,执行add3这个方法, toString 和 valueOf 是隐式调用的,隐式调用发生在什么时候呢?

当函数执行 func3(1)(2)(3)(4); 完成这一行代码的时候,并没有执行隐式调用执行了 console.log(func3(1)(2)(3)(4)) 这一行代码,toString 才执行, 我并不是很清楚为什么会这样,我的理解是这样的,toString 和 valueOf 这两个函数的作用返回的是当前函数的值, func3(1)(2)(3)(4), 这一行代码虽然有返回值,但是并没有用到,所以并不执行toString和valueOf,而这一行 console.log(func3(1)(2)(3)(4)) 我们用到了,我们把值传进了 console.log()函数,用到了这个值,所以会执行 toString和valueOf,得出结论,值被用到就会执行 toString和valueOf

隐式调用比较常见的 if 判断条件里边的类型转换,操作符,函数传参,只要值被用到,就会发生隐式调用。

推荐阅读:柯里化与反柯里化

水平有限,简单的实现,难免有错误,欢迎指出。