Question about proxies and non-class inheritance with private fields

# email at trevormccauley.com (7 years ago)

Given "Private fields are designed to have semantics analogous to WeakMaps" (tc39.github.io/proposal-class-fields/#sec-private-names) and "All ECMAScript objects, including Proxies, and any user exotic object, should have a [[PrivateFieldValues]] internal slot iniitlaized to an empty List." (tc39.github.io/proposal-class-fields/#sec-objectcreate), does this mean the implementation of private fields will break uses of Object.create and Proxy usage as user-defined WeakMap implementations do now?

For example:

const priv = new WeakMap()

class Foo {
   constructor () {
     priv.set(this, 'data')
   }
   logChar () {
     console.log(priv.get(this).charAt(0))
   }
}

new Foo().logChar() //-> 'd'

Object.create(new Foo()).logChar() // Err: no charAt in undefined
new Proxy(new Foo(), {}).logChar() // Err: no charAt in undefined

The problem being that this in logChar for the created object and proxy are different instances than the this associated with the private map's 'data'. So the "private slots" of those instances do not match the objects they wrap, instead being empty/uninitialized.

I figured proxies would at least need to be able to handle situations like this. An example on MDN shows a proxy using methods like setItem() and getItem() from its target which, if implemented with private data, would could cause failures like the one seen above (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#A_complete_traps_list_example). I've seen mention of the "proxy problem" in various places with respect to private fields but wasn't sure if there was a solution in place for it - or even if it necessarily referred to what I'm describing here.
But the observations above suggests that using proxies may not be safe - at least not without familiarity with the implementation of the object you're proxying. So I just want to make sure I understand it correctly.

Thanks, Trevor

# Oriol _ (7 years ago)

A proxy object emulates its target because the essential internal methods are redirected to the target by default. However, this does not happen with other internal slots, so I don't see why it should be different for private fields. More examples:

new Number(123).valueOf(); // 123
new Proxy(new Number(123), {}).valueOf(); // TypeError: valueOf method called on incompatible Proxy
new Set().has(1); // false
new Proxy(new Set(), {}).has(1); // TypeError: has method called on incompatible Proxy
// Assuming a web browser
document.nodeType; // 9
new Proxy(document, {}).nodeType; // TypeError: 'get nodeType' called on an object that does not implement interface Node.
# email at trevormccauley.com (7 years ago)

However, this does not happen with other internal slots, so I don't see why it should be different for private fields.

Yup, that makes sense, and it looks like its not something I've not run into before. That answers my question,