手写柯里化 - toString 理解

简介: 柯里化可以通过闭包+递归实现

image.png

在前面一篇文章《为什么我要说:柯里化 == 闭包+递归? 》中,我们提到:


柯里化可以通过闭包+递归实现


let arr = []
function addCurry() {
   let arg = Array.prototype.slice.call(arguments); // 收集参数
   arr = arr.concat(arg);
    if (arg.length === 0) { // 如果参数为空,则判断递归结束
        return arr.reduce((a,b)=>{return a+b}) // 求和
    } else {
        return addCurry;
    }
}
addCurry(1)(2)(3)() // 6


这样写,没什么毛病,通过:Array.prototype.slice.call(arguments) 收集了参数,推到 arr 数组里;当存在参数时,递归调用,当没有参数的时候,再用 reduce() 求和,返回;


但是这样写,会有外部变量 arr,arr 不清理的话,会被一直保存,导致连续调用出错:


addCurry(1)(2)(3)() // 6
addCurry(1)() // 7


所以,需要改写成这样:


function addCurry() {
    let arr = [...arguments]
    let fn = function () {
        if(arguments.length === 0) {
      return arr.reduce((a, b) => a + b)
        } else {
            arr.push(...arguments)
            return fn
        }
    }
    return fn
}


把 arr 再加一层封装到函数里,每次调用,都会重新声明,原值会被清理;

之前相加的思路仍然不变;


但这样做,还有一个问题:总是需要用空括号 () 为结尾,来判断结束调用;

能不能去掉这个,直接如下这样就能求值:


addCurry(1)(2)(3)
//或
addCurry(1)(2,3)


答案是可以的,原理是用到 toString ,当用 Function 的值做计算的时候,会调用 toString 做隐式转换;


let fn = function(){}
fn.toString = () => 1
fn == 1 // true


所以,我们的代码更新为:


function addCurry() {
    let arr = [...arguments]
    // 利用闭包的特性收集所有参数值
    var fn = function() {
        arr.push(...arguments);
        return fn;
    };
    // 利用 toString 隐式转换
    fn.toString = function () {
        return arr.reduce(function (a, b) {
            return a + b;
        });
    }
    return fn;
}
addCurry(1)(2)(3) == 6 // true


这里一定要注意,直接打印 addCurry(1)(2)(3) 是不能拿值的,只有当它做隐式转化的时候,才能计算得正确得值。


小结:


其实不管是用空括号 () 作“开始执行reduce相加”的判断依据,还是用 toString 的隐式转换做依据,总是要有一个标准,来告诉柯里化函数:你可以执行了!

柯里化精髓是参数收集,是延迟执行!

延迟就是 JS 函数闭包的精髓设计!!


相关文章
|
6月前
13 # 手写 concat 方法
13 # 手写 concat 方法
58 0
|
6月前
03 # 手写 call
03 # 手写 call
41 0
|
前端开发
手写基础 promise
手写基础 promise
66 0
|
存储 前端开发
|
前端开发
Promise的用法&原理&手写实现-2
Promise的用法&原理&手写实现-2
42 1
|
6月前
|
Java 编译器 Linux
【C++11(二)】lambda表达式以及function包装器
【C++11(二)】lambda表达式以及function包装器
|
6月前
|
索引
12 # 手写 findIndex 方法
12 # 手写 findIndex 方法
52 0
|
6月前
|
索引
06 # 手写 map 方法
06 # 手写 map 方法
54 0
|
前端开发 JavaScript API
Promise的用法&原理&手写实现-1
Promise的用法&原理&手写实现-1
57 0
手写函数柯里化原理
手写函数柯里化原理记录
60 1