简体   繁体   中英

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

My friend sent this picture to me, shows the function add that can chain numbers indefinitely, then output the sum.

截屏

I was thinking of using Proxy to add key numbers together and rewrite its Symbol.toPrimitive function, but it seems it doesn't work and I'm not sure what is going on...

Am I on the right direction or is there a better way to do it?

 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]);

Your problem is that this inside of your [Symbol.toPrimitive](){} method is your proxy, and not your target object (ie: your first object argument to the proxy constructor). This causes your proxy get trap to trigger, which results in your toPrimitive method not returning a primitive, but instead an object (and so your code throws). This is because, when you perform:

console.log(+add[1]);

you are converting the Proxy ( add[1] ) to a primitive number value. When this occurs, JavaScript will try and grab the Symbol.toPrimitive function from that proxy. When that occurs, your get trap in your handler object runs, and returns the Symbol.toPrimitive function object defined on your target object. The engine then invokes this returned function with the this value set to the proxy ( not the handler object). In code, you can think of the following occurring when JS converts your proxy, add[1] , to a number:

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` !!

The above steps are outlined in the spec here . As you can see from the last line, your Symbol.toPrimitive() function is invoked with this set as your proxy value, which results in the following code also causing your get trap to fire:

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

above, this.value triggers your get method in your handler object to fire with a key of value , as this represents your proxy, causing the get trap to trigger. Because your get trap returns a proxy when key is set to value , your Symbol.toPrimitive method doesn't return a primitive, but rather it returns your app proxy, which causes your code to throw. A simple quick fix is to handle the case when value is accessed on your object (note that I've also reset value so that each log doesn't accumulate from the previous):

 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]);

Another option is to change the toPrimitive function that gets invoked, which you can do by returning a function that wraps your toPrimitive function and invokes it with a new this value that is set to the target object. You can also reset your value count in this new wrapper function:

 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]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM