> `o.foo(); // works`

I think there is something missing from that example as that line
throws before it can get to the `new Proxy` line.

#!/JoePea

On Wed, Jul 15, 2020 at 10:47 PM Jordan Harband <[email protected]> wrote:
>
> So can:
> ```jsx
> const o = { foo() { if (o.foo !== this) { throw 'detected'; } } };
> o.foo(); // works
> new Proxy(o, {}).foo(); // throws
> ```
>
> (as would a class that used a closed-over WeakMap for each "private field")
>
> Private fields do not introduce any new hazards here.
>
> On Tue, Jul 14, 2020 at 8:18 PM #!/JoePea <[email protected]> wrote:
>>
>> >  private members (safely) allow classes with internal slots.
>>
>> I'd say that they aren't safe, if they can break 3rd-party code on the
>> external public side.
>>
>> #!/JoePea
>>
>> On Sun, Jul 12, 2020 at 3:09 PM Michael Theriot
>> <[email protected]> wrote:
>> >
>> > I assume OP wants to use proxies and private members together. They are 
>> > not designed to be compatible.
>> >
>> > Proxies and private members are a UX goal primarily for developers. 
>> > Proxies easily allow observation of another object or creation of exotic 
>> > objects (e.g. Array), and private members (safely) allow classes with 
>> > internal slots. Since they cannot be used together the issue exists, and 
>> > the hack circumvents this by reimplementing private in a way that does not 
>> > require private fields.
>> >
>> > On Sun, Jul 12, 2020 at 4:45 PM kai zhu <[email protected]> wrote:
>> >>
>> >> as product-developer, can i ask what ux-objective you ultimately want 
>> >> achieved?
>> >>
>> >> ```js
>> >> const sub = new Sub()
>> >>
>> >> // i'm a noob on proxies. what is this thing (with 
>> >> proxied-private-fields) ultimately used for?
>> >> const proxy = new Proxy(sub, ...)
>> >> ```
>> >>
>> >> On Sun, Jul 12, 2020 at 4:34 PM Michael Theriot 
>> >> <[email protected]> wrote:
>> >>>
>> >>> This does require you to have both the key and the weakmap though, so it 
>> >>> actually does succeed in hiding the data so long as the weakmap is out 
>> >>> of scope. I guess the issue I can foresee is that the key could be 
>> >>> modified after the object is created.
>> >>>
>> >>> e.g.
>> >>> ```js
>> >>> var a = new A();
>> >>> var key = Object.getOwnPropertySymbols(a)[0];
>> >>> delete a[key];
>> >>> a.hidden; // throws
>> >>> ```
>> >>>
>> >>> That itself can be guarded by just making the key undeletable. So, I 
>> >>> guess this solution could work depending what your goals are?
>> >>>
>> >>> On Sun, Jul 12, 2020 at 4:21 PM Michael Theriot 
>> >>> <[email protected]> wrote:
>> >>>>
>> >>>> It nearly works, but the issue is that the key will be leaked by 
>> >>>> `Object.getOwnPropertySymbols(new A())`, so it's not truly private.
>> >>>>
>> >>>> There have been ideas proposing "private symbols" but I am not familiar 
>> >>>> with their issues, and I would guess with Class Fields they are 
>> >>>> unlikely to materialize anyway.
>> >>>>
>> >>>> On Sun, Jul 12, 2020 at 2:19 PM François REMY 
>> >>>> <[email protected]> wrote:
>> >>>>>
>> >>>>> At the risk of pointing out the obvious:
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> ```js
>> >>>>>
>> >>>>> const privkey = Symbol();
>> >>>>>
>> >>>>> const stores = new WeakMap();
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> class A {
>> >>>>>
>> >>>>>   [privkey] = {};
>> >>>>>
>> >>>>>   constructor() {
>> >>>>>
>> >>>>>     const priv = {};
>> >>>>>
>> >>>>>     priv.hidden = Math.random();
>> >>>>>
>> >>>>>     stores.set(this[privkey], priv);
>> >>>>>
>> >>>>>   }
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>>   get hidden() {
>> >>>>>
>> >>>>>     const priv = stores.get(this[privkey]);
>> >>>>>
>> >>>>>     return priv.hidden;
>> >>>>>
>> >>>>>   }
>> >>>>>
>> >>>>> }
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> var as = [
>> >>>>>
>> >>>>>                 new A(),
>> >>>>>
>> >>>>>                 new Proxy(new A(),{}),
>> >>>>>
>> >>>>>                 new Proxy(new A(),{}),
>> >>>>>
>> >>>>> ];
>> >>>>>
>> >>>>> console.log(as.map(a=>a.hidden));
>> >>>>>
>> >>>>> ```
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> From: Michael Theriot
>> >>>>> Sent: Sunday, July 12, 2020 20:59
>> >>>>> To: Michael Haufe
>> >>>>> Cc: [email protected]
>> >>>>> Subject: Re: Why does a JavaScript class getter for a private field 
>> >>>>> fail using a Proxy?
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> I experienced this issue prior to this proposal, using weakmaps for 
>> >>>>> private access.
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> e.g.
>> >>>>>
>> >>>>> ```js
>> >>>>>
>> >>>>> const stores = new WeakMap();
>> >>>>>
>> >>>>> class A {
>> >>>>>   constructor() {
>> >>>>>     const priv = {};
>> >>>>>     priv.hidden = 0;
>> >>>>>     stores.set(this, priv);
>> >>>>>   }
>> >>>>>
>> >>>>>   get hidden() {
>> >>>>>     const priv = stores.get(this);
>> >>>>>     return priv.hidden;
>> >>>>>   }
>> >>>>> }
>> >>>>>
>> >>>>> const a = new A();
>> >>>>> console.log(a.hidden); // 0
>> >>>>>
>> >>>>> const p = new Proxy(a, {});
>> >>>>> console.log(p.hidden); // throws!
>> >>>>>
>> >>>>> ```
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> I found a workaround:
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> ```js
>> >>>>> const stores = new WeakMap();
>> >>>>>
>> >>>>> class A {
>> >>>>>   constructor() {
>> >>>>>     const priv = {};
>> >>>>>     priv.hidden = 0;
>> >>>>>     stores.set(this, priv);
>> >>>>>
>> >>>>>     const p = new Proxy(this, {});
>> >>>>>     stores.set(p, priv); // set proxy to map to the same private store
>> >>>>>
>> >>>>>     return p;
>> >>>>>   }
>> >>>>>
>> >>>>>   get hidden() {
>> >>>>>     const priv = stores.get(this); // the original instance and proxy 
>> >>>>> both map to the same private store now
>> >>>>>     return priv.hidden;
>> >>>>>   }
>> >>>>> }
>> >>>>>
>> >>>>> const a = new A();
>> >>>>>
>> >>>>> console.log(a.hidden);
>> >>>>> ```
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> Not ideal, and only works if you provide the proxy in the first place 
>> >>>>> (e.g. making exotic JS objects). But, not necessarily a new issue with 
>> >>>>> proxies, either.
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> On Fri, Jun 5, 2020 at 12:29 AM Michael Haufe 
>> >>>>> <[email protected]> wrote:
>> >>>>>
>> >>>>> This is a known issue and very painful for me as well. You can see a 
>> >>>>> long ugly discussion here:
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> <https://github.com/tc39/proposal-class-fields/issues/106>
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> I suggest the following guide to assist you:
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> <https://javascript.info/proxy#proxy-limitations>
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> Another possible approach is to have your classes extend a proxy:
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> <https://github.com/tc39/proposal-class-fields/issues/106#issuecomment-397484713>
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> From: es-discuss <[email protected]> On Behalf Of Laurie 
>> >>>>> Harper
>> >>>>> Sent: Friday, June 5, 2020 12:21 AM
>> >>>>> To: [email protected]
>> >>>>> Subject: Why does a JavaScript class getter for a private field fail 
>> >>>>> using a Proxy?
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> I can expose private class fields in JavaScript using getters, and 
>> >>>>> those getters work correctly when invoked on instances of a subclass. 
>> >>>>> However, if I then wrap the instance with a proxy the getter will 
>> >>>>> throw a type error, even if the proxy `get` hook uses `Reflect.get()`:
>> >>>>>
>> >>>>> ```
>> >>>>> class Base {
>> >>>>>     _attrA
>> >>>>>     #_attrB
>> >>>>>
>> >>>>>     constructor() {
>> >>>>>         this._attrA = 100
>> >>>>>         this.#_attrB = 200
>> >>>>>     }
>> >>>>>
>> >>>>>     get A() { return this._attrA }
>> >>>>>
>> >>>>>     get B() { return this.#_attrB }
>> >>>>>
>> >>>>>     incrA() { this._attrA++ }
>> >>>>>
>> >>>>>     incrB() { this.#_attrB++ }
>> >>>>> }
>> >>>>>
>> >>>>> class Sub extends Base {}
>> >>>>>
>> >>>>> const sub = new Sub()
>> >>>>>
>> >>>>> const proxy = new Proxy(sub, {
>> >>>>>     get(target, prop, receiver) {
>> >>>>>         const value = Reflect.get(target, prop, receiver)
>> >>>>>         return typeof value === 'function' ? value.bind(target) : 
>> >>>>> value // (1)
>> >>>>>     }
>> >>>>> })
>> >>>>>
>> >>>>> console.log('sub.A', sub.A) // OK: -> 100
>> >>>>> console.log('sub.B', sub.B) // OK: -> 200
>> >>>>> sub.incrA() // OK
>> >>>>> sub.incrB() // OK
>> >>>>> console.log('sub.A', sub.A) // OK: -> 101
>> >>>>> console.log('sub.B', sub.B) // OK: -> 201
>> >>>>>
>> >>>>> console.log('proxy.A', proxy.A) // OK: -> 100
>> >>>>> console.log('proxy.B', proxy.B) // TypeError: Cannot read private 
>> >>>>> member #_attrB from an object whose class did not declare it
>> >>>>> proxy.incrA() // OK
>> >>>>> proxy.incrB() // OK due to (1)
>> >>>>> console.log('proxy.A', proxy.A) // OK: -> 100
>> >>>>> console.log('proxy.B', proxy.B) // TypeError: Cannot read private 
>> >>>>> member #_attrB from an object whose class did not declare it
>> >>>>> ```
>> >>>>>
>> >>>>> The call to `proxy.incrB()` works, because the proxy handler 
>> >>>>> explicitly binds function values to `target` on line (1). Without the 
>> >>>>> `bind()` call, the `proxy.incrB()` invocation would throw a 
>> >>>>> `TypeError` like the getter invocation does. That makes some sense: 
>> >>>>> the result of the call to `Reflect.get()` is the 'unbound' function 
>> >>>>> value of the property being retrieved, which must then be bound to 
>> >>>>> `target`; it would make more sense, though, if `this` binding was 
>> >>>>> applied by the [[Call]] operation on the result of the [[Get]] 
>> >>>>> operation...
>> >>>>>
>> >>>>> But there is no opportunity to 'bind' a getter before invoking it; as 
>> >>>>> a result, a proxied getter ends up receiving the wrong `this` binding, 
>> >>>>> leading to the inconsistency.
>> >>>>>
>> >>>>> Is there any way to make this work correctly? The only approach I can 
>> >>>>> think of (which I haven't tried) would be to have the `get` hook walk 
>> >>>>> up the prototype chain, starting from `target`, calling 
>> >>>>> `getOwnPropertyDescriptor()` and checking for a getter method, and 
>> >>>>> explicitly applying the getter with an adjusted `this` binding. That 
>> >>>>> sounds ludicrously cumbersome and brittle...
>> >>>>>
>> >>>>> Is there a better way to get this working correctly?
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> --
>> >>>>>
>> >>>>> Laurie
>> >>>>>
>> >>>>> _______________________________________________
>> >>>>> es-discuss mailing list
>> >>>>> [email protected]
>> >>>>> https://mail.mozilla.org/listinfo/es-discuss
>> >>>>>
>> >>>>>
>> >>>
>> >>> _______________________________________________
>> >>> es-discuss mailing list
>> >>> [email protected]
>> >>> https://mail.mozilla.org/listinfo/es-discuss
>> >
>> > _______________________________________________
>> > es-discuss mailing list
>> > [email protected]
>> > https://mail.mozilla.org/listinfo/es-discuss
>> _______________________________________________
>> es-discuss mailing list
>> [email protected]
>> https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to