如何使用方括号表示法实现此 curry 函数 "add"?

How do I achieve this curry function "add" with square bracket notation?

我朋友发给我的这张图片,显示了可以无限链数,然后输出总和的函数add

我想用Proxy把关键数字加在一起,然后重写它的Symbol.toPrimitive函数,但是好像不行,我也不知道是怎么回事.. .

我的方向是否正确,或者有更好的方法吗?

let add = new Proxy(
  {
    [Symbol.toPrimitive]() {
      return this.value;
    },
    value: 0
  },
  {
    get(target, key, receiver) {
      if(Symbol.toPrimitive === key) {
        return target[Symbol.toPrimitive];
      } else if (!isNaN(key)) {
        target.value += +key;
      }
      return add;
    },
  }
);

console.log(+add[1]);
console.log(+add[1][2][3]);
console.log(+add[10][-5][3][100]);

您的问题是 [Symbole.toPrimitive](){} 方法中的 this 是您的代理,而不是您的 target 对象(即:代理构造函数的第一个对象参数)。这会导致您的代理获取陷阱触发,从而导致您的 toPrimitive 方法不是 returning 原语,而是一个对象(因此您的代码会抛出)。这是因为,当您执行:

console.log(+add[1]);

您正在将代理 (add[1]) 转换为原始数值。发生这种情况时,JavaScript 将尝试从该代理获取 Symbol.toPrimitive 函数。发生这种情况时,您的处理程序对象中的 get 陷阱将运行,并且 return 是在目标对象上定义的 Symbol.toPrimitive 函数对象。然后引擎调用此 returned 函数,并将 this 设置为代理 不是 处理程序对象) .在代码中,你可以想到当 JS 将你的代理 add[1] 转换为数字时会发生以下情况:

const input = add[1]; // your proxy
const exoticToPrim = input[Symbol.toPrimitive]; // gets the Symbol.toPrimitive function from your object
const result = exoticToPrim.call(input, "number"); // !! calls `Symbol.toPrimitive` !!

规范 here 中概述了上述步骤。从最后一行可以看出,调用 Symbol.toPrimitive() 函数时将 this 设置为您的代理值,这会导致以下代码也导致您的 get 陷阱触发:

[Symbol.toPrimitive]() {
  return this.value;
}

上面,this.value 触发您的处理程序对象中的 get 方法以 value 键触发,因为 this 代表您的代理,导致 get 陷阱触发。因为当 key 设置为 value 时,您的 get trap return 是代理,所以您的 Symbol.toPrimitive 方法不是 return 原语,而是 returns 你的 app 代理,这会导致你的代码抛出。一个简单的快速修复是处理在您的对象上访问 value 的情况(请注意,我还重置了 value 以便每个日志都不会从以前的日志中累积):

let add = new Proxy(
  {
    [Symbol.toPrimitive]() {
      return this.value;
    },
    value: 0
  },
  {
    get(target, key, receiver) {
      if(key === Symbol.toPrimitive) {        
        return target[key];
      } else if(key === 'value') {
        const sum = target[key];
        target[key] = 0;
        return sum;
      } else if (!isNaN(key)) {
        target.value += +key;
      }
      return add;
    },
  }
);

console.log(+add[1]);
console.log(+add[1][2][3]);
console.log(+add[10][-5][3][100]);

另一种选择是更改被调用的 toPrimitive 函数,您可以通过 return 包装您的 toPrimitive 函数并使用新的 this 设置到 target 对象的值。您还可以在这个新的包装函数中重置您的价值计数:

let add = new Proxy(
  {
    [Symbol.toPrimitive]() {
      return this.value;
    },
    value: 0
  },
  {
    get(target, key, receiver) {
      if(key === Symbol.toPrimitive) {        
        return (...args) => {
          const prim = target[key].apply(target, args);
          target.value = 0;
          return prim;
        };
      } else if (!isNaN(key)) {
        target.value += +key;
      }
      return add;
    },
  }
);

console.log(+add[1]);
console.log(+add[1][2][3]);
console.log(+add[10][-5][3][100]);