Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何实现一个柯里化的累加函数? #19

Open
luckept opened this issue Jun 21, 2022 · 5 comments
Open

如何实现一个柯里化的累加函数? #19

luckept opened this issue Jun 21, 2022 · 5 comments
Labels

Comments

@luckept
Copy link
Member

luckept commented Jun 21, 2022

要求如下

function sum() {
}

const total = +sum(1)(2, 3)(3)
console.log("total => ", total) // total => 9

最终实现的迷惑版

function sum(...nums) {
  let acc = 0
  const fn = (...nums) => (acc = nums.reduce((acc, cur) => acc + cur, acc), fn)
  fn[Symbol.toPrimitive] = () => acc
  return fn(...nums)
}

如何理解上述最终实现

一行一行分析,第一步创建 acc = 0,其实是为了迷惑而迷惑,完全可以命名成其他诸如 sum 之类好理解的变量名,它的目的是用来闭包留存累加结果

第二步,如何理解形式为 const fn = () => (xxx, fn) 的代码

// 上述代码效果其实和这段代码一样
function fn() {
    xxx // 函数核心逻辑,此处省略
    return fn
}

而简写版只是为了利用逗号返回后一个值的特性,来省略代码

第三步,理解 acc = nums.reduce((acc, cur) => acc + cur, acc)

这里首先去掉迷惑的命名来理解,把闭包变量改名为 sum,上述代码变为 sum = nums.reduce((acc, cur) => acc + cur, sum),要注意的是这里的后一个 sum 就不再是利用逗号运算符的特性去返回 sum 了,而是每次让柯里化的闭包累加结果作为下一次 reduce 函数的初始值

第四步,理解 fn[Symbol.toPrimitive] = () => acc

因为柯里化的返回结果永远是一个函数,而我们如何去通过这个函数获取到闭包对象的值呢?这里按题目要求可以看见最终输出的时候利用了 + 号,这会触发函数的转换,而 [Symbol.toPrimitive] 则可以定义转换的规则,把闭包值作为转换后的结果(当然,这里也可以利用 valueOf 和 toString)

@luckept
Copy link
Member Author

luckept commented Jun 21, 2022

此处补充一个知识点,关于使用运算符来使匿名函数立即执行(PS:和本题的场景无关)

! function(x, y) { console.log(x + y) } (1, 2) // 3
+ function(x, y) { console.log(x + y) } (1, 2) // 3
- function(x, y) { console.log(x + y) } (1, 2) // 3
~ function(x, y) { console.log(x + y) } (1, 2) // 3
void function(x, y) { console.log(x + y) } (1, 2) // 3

@Hongbusi Hongbusi added the today 每日一题。 label Jun 22, 2022
@jp-liu
Copy link

jp-liu commented Jun 22, 2022

function sum() {
    let sum = 0
    function t(...args){
        sum += args.reduce((a,b) => a + b, 0)
        return t
    }
    t.valueOf = function() {
        return sum
    }
    t.toString = function () {
        return sum+ ''
    }
    return t(...arguments)
}

不知是否可行

@luckept
Copy link
Member Author

luckept commented Jun 22, 2022

发一个可能会被同事打的迷惑版

function sum(...nums) {
  let acc = 0
  const fn = (...nums) => (acc = nums.reduce((acc, cur) => acc + cur, acc), fn)
  fn[Symbol.toPrimitive] = () => acc
  return fn(...nums)
}

@Hongbusi
Copy link
Member

@luckept 可能二字去掉!

@baboon-king
Copy link

发个 Typescript 版 🙈

const curry = <T extends (...args: any[]) => any>(fn: T, maxArgsLen = 99) => {
  const argsLen = fn.length || maxArgsLen;
  const argList: any[] = [];
  const callback = (...args: any[]) => {
    argList.push(...args);
    if (argList.length >= argsLen || args.length === 0) {
      return fn(...argList);
    } else {
      return callback;
    }
  };
  return callback;
};

// test 1
const sum = (num1: number, num2: number, num3: number) => num1 + num2 + num3;

const curredSum = curry(sum);

console.log(curredSum(1)(2)(9));

// test 2
const sumAny = (...args: number[]) => args.reduce((pre, curr) => pre + curr);

const curredSumAny = curry(sumAny, 5);

console.log(curredSumAny(1, 2, 3)(2)());

// test 3
const curredSumAny2 = curry(sumAny, 5);
console.log(curredSumAny2(1, 2, 3)(2)(1000));

image

@Hongbusi Hongbusi removed the today 每日一题。 label Jun 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

4 participants