1

I want to use javascript's Proxy objects to augment a data structure with a bit of additional logging. While doing so, I noticed a problem:

simpleProxy = new Proxy(new Number(4), {})
simpleProxy.valueOf(); // TypeError: valueOf method called on incompatible Proxy

The error makes sense to me. valueOf is invoked with the this object set to the Proxy instead of the Number object thus leading to a type error.

The problem to me now is that in user code it is actually useful to propagate the Proxy as the this value into function calls so that access to properties is done through the proxy. Only when calling "low-level" routines like the above do I get in trouble. The question: How can I reliably detect that I'd be calling such a Proxy incompatible function, possibly assuming for a moment that user defined functions are safe to call?


This is not asking if the called function is a native function. Only certain native functions can not handle Proxy values. Besides, the detection in the linked question is rather unsound and would require different special cases here. Consider a function linked from a native interface. It may very well be able to operate on a proxy value, thus detecting it as a native function would be a false positive.

Currently, I believe the best approach is to find out if the target in get is primitive by calling target.valueOf() first instead of infering anything from whether the function is native or not. As such, this is not a duplicate.

WorldSEnder
  • 4,875
  • 2
  • 28
  • 64

1 Answers1

1

First we check if the Property is from the prototype or from the target itself, if not and the key is that of a method, we return an anonymous function that passes its arguments into the method with the appropriate this when called.

Note: I'm not entirely sure if this is foolproof.

let a = new Proxy(new Number(3), {
  get(target, key) {
    if (!target.hasOwnProperty(key) && typeof target[key] === "function") {
      return function(...args) {
        return target[key].call(target, args);
      }
    }
    return target[key];
  }
});

console.log( a.valueOf() );
zfrisch
  • 8,474
  • 1
  • 22
  • 34
  • I have researched a bit. Builtin functions are a problem, specifically because they specify thing like [thisNumberValue](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-thisnumbervalue) that accesses internal slots. All user code must call `valueOf` or use one of the builtin methods, anyway. I think what I'll do is special case all of these internal methods, even if it's not pretty. Your solution catches a bit too much, for example inherited methods. – WorldSEnder Mar 05 '18 at 20:06