js实现参数定长/不定长的柯里化

文章原文: https://www.cnblogs.com/yalong/p/14298085.html

题目1:把一个计算加法的函数fn 进行柯里化,其中fn 分为 参数个数固定 和 参数个数不固定两种

参数个数固定的柯里化实现:

  function fn(a, b, c) {
    return a + b + c
  }
  function curry(fn) {
    // 获取原函数的参数长度
    const argLen = fn.length;
    // 保存预置参数, 当预置参数 有三个的时候 直接返回了函数,需要单独执行一次
    const presetArgs = [].slice.call(arguments, 1)
    // 返回一个新函数
    return function() {
      // 新函数调用时会继续传参
      const restArgs = [].slice.call(arguments)
      const allArgs = [...presetArgs, ...restArgs]
      if (allArgs.length >= argLen) {
        // 如果参数够了,就执行原函数
        return fn.apply(null, allArgs)
      } else {
        // 否则继续柯里化
        return curry.call(null, fn, ...allArgs)
      }
    }
  }

  // 用例一
  let c1 = curry(fn, 1);
  let c2 = curry(c1, 2);
  let c3 = curry(c2, 3);
  console.log(c3()) // 6

  // 用例二
  let curried = curry(fn);
  console.log(curried(1, 2, 3)) // 6
  console.log(curried(1, 2)(3)) // 6
  console.log(curried(1)(2, 3)) // 6
  console.log(curried(1)(2)(3)) // 6

  // 用例三
  // 注意这个, 因为初始的时候 把参数全部传进去了,导致返回的是一个函数, 没能走到 apply 的立即执行
  console.log(curry(fn, 1, 2, 3)()) // 6
  console.log(curry(fn, 1, 2)(3)) // 6
  console.log(curry(fn, 1)(2, 3)) // 6
  console.log(curry(fn, 1)(2)(3)) // 6

参数个数不固定的柯里化实现

 function curry(fn) {
  // 保存预置参数
  const presetArgs = [].slice.call(arguments, 1)
  // 返回一个新函数
  function curried () {
    // 新函数调用时会继续传参
    const restArgs = [].slice.call(arguments)
    const allArgs = [...presetArgs, ...restArgs]
    // 下面这个相当于 return currl(fn, ...allArgs)
    return curry.call(null, fn, ...allArgs)
  }
  // 重写toString
  curried.toString = function() {
    return fn.apply(null, presetArgs)
    // 下面这个是一样的
    // return fn.call(null, ...presetArgs)
  }
  return curried;
}

function fn() {
  return [...arguments].reduce((prev, curr) => {
    return prev + curr
  }, 0)
}
var add = curry(fn);
console.log(add(1)(2)(3)(4)) // 10
console.log(add(1, 2)(3, 4)(5, 6)) // 21

题目2: 实现add(1)(2)(3)(4)的打印结果为10,并且要求可以随意调用,不过每次只传一个参数,如add(1)(2)(3)(4)(5)的打印结果为15
实现代码如下:

function add(x) {
    let sum = x;
    let tmp = function (y) {
        sum = sum + y;
        return tmp;
    };
    tmp.toString = function () {
        return sum;
    };
    return tmp;
}
console.log(add(1)(2)(3) + '') // 6
console.log(add(1)(2)(3)(4) + '') // 10
console.log(add(1)(2)(3)(4)(5) + '') // 15

题目3: 实现add(1, 2)(3)的打印结果为6,add(1)(2, 3, 4)(5) 结果为15, 意思就是 传递的参数个数不固定
实现代码如下:

function add () {
    let args = [...arguments];
    let fn = function () {
        args.push(...arguments);
        return fn
    }
    fn.toString=function(){
        return args.reduce((a, b) => {
            return a + b
        })
    }
    return fn
}
console.log(add(1, 2)(3) + '') // 6
console.log(add(1)(1,2,3)(2) + '') // 9
console.log(add(1)(2, 3, 4)(5) + '') // 15

上面用到了toString 这里就联想到了valueOf 这两者的区别简单来说如下:

  • valueOf():返回最适合该对象类型的原始值
  • toString(): 将该对象的原始值以字符串形式返回

这两个方法一般是交由JS去隐式调用,以满足不同的运算情况。
在数值运算里,会优先调用valueOf(),如a + b
在字符串运算里,会优先调用toString(),如alert(c)。
当然更深入的说法还有,不过这里就不讨论了。

posted @ 2021-01-22 11:07  进军的蜗牛  阅读(2193)  评论(0编辑  收藏  举报