Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Set Incompatible with Proxy?

JavaScript Set appears to be entirely incompatible with JavaScript proxies, attempting to Proxy() a Set()

var p = new Proxy(new Set(), {
  add(target, val, receiver) {
    console.log('in add: ', target, val, receiver)
  }
})
p.add(55)

results in a VMError:

Uncaught TypeError: Method Set.prototype.add called on incompatible receiver [object Object]
    at Proxy.add (native)
    at <anonymous>:1:3

In fact, proxying a Set() in any way breaks it categorically - even if our proxy handler does nothing at all! Compare p = new Proxy({}, {}) vs p = new Proxy(new Set(), {}). (This applies both in Firefox (52.0.2) and Chromium (57.0.2987.133).)

I can't seem to find a credible reference or documentation for this, why cannot JavaScript Proxy a Set object and why is it hitting a VM Error?

like image 726
user3467349 Avatar asked May 12 '17 01:05

user3467349


People also ask

What is proxy in console log?

The Proxy object allows you to create an object that can be used in place of the original object, but which may redefine fundamental Object operations like getting, setting, and defining properties. Proxy objects are commonly used to log property accesses, validate, format, or sanitize inputs, and so on.

Why proxy is used in JavaScript?

In JavaScript, proxies (proxy object) are used to wrap an object and redefine various operations into the object such as reading, insertion, validation, etc. Proxy allows you to add custom behavior to an object or a function.

What is ES6 proxy?

ES6 implements intercession form of meta programming using Proxies. Similar to ReflectAPI, the Proxy API is another way of implementing meta programming in ES6. The Proxy object is used to define custom behavior for fundamental operations. A proxy object performs some operations on behalf of the real object.

What is proxy handler?

The proxy handler inspects incoming requests for the custom request headers through which the proxy server conveys the information about the original client request, and makes this information available to the web application on the Application Server using standard ServletRequest APIs.


1 Answers

I am attempting to Proxy() a Set()

However, you haven't used any of the available traps - there is no add one. All that you can intercept in the call p.add(55) is the property access to .add on the proxy, which goes through the get trap and returns a function.

If you want to intercept calls to the add method, you don't need a proxy at all, better (subclass and) overwrite that method similar to how .set was overridden here and here for Map.

proxying a Set() in any way breaks it categorically

Yes, because the proxy is not a Set any more.

var s = new Set([42]);
var p = new Proxy(s, {});
s.has(42) // true
console.log(s === p) // false
p.has.call(s, 42) // true
p.has(42) // exception - calls `has` on `p`, not on `s`

Calling Set methods on objects that are no True Sets does throw an exception (which e.g. can be used for detecting them). For your particular case, see ECMAScript 6 §23.2.3.1:

"If S does not have a [[SetData]] internal slot, throw a TypeError exception."

And indeed, p is a proxy (which does have the internal Proxy methods and slots, especially [[ProxyHandler]] and [[ProxyTarget]]) instead of a set like s with its [[SetData]] internal slot.

You reasonably were expecting that "if a trap has not been defined, the default behavior is to forward the operation to the target", however that only applies to standard behaviours like property access, and not the internal slots of exotic objects.

like image 170
Bergi Avatar answered Oct 23 '22 20:10

Bergi