zoukankan      html  css  js  c++  java
  • 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)。
    当然更深入的说法还有,不过这里就不讨论了。

  • 相关阅读:
    1058 A+B in Hogwarts (20)
    1046 Shortest Distance (20)
    1061 Dating (20)
    1041 Be Unique (20)
    1015 Reversible Primes (20)(20 分)
    pat 1027 Colors in Mars (20)
    PAT 1008 Elevator (20)
    操作系统 死锁
    Ajax的get方式传值 避免& 与= 号
    让IE浏览器支持CSS3表现
  • 原文地址:https://www.cnblogs.com/yalong/p/14298085.html
Copyright © 2011-2022 走看看