oh oops, i meant `if (o !== this)` not `if (o.foo !== this)` :-) On Mon, Jul 27, 2020 at 3:06 PM #!/JoePea <j...@trusktr.io> wrote:
> > `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 <ljh...@gmail.com> 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 <j...@trusktr.io> 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 > >> <michael.lee.ther...@gmail.com> 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 <kaizhu...@gmail.com> 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 < > michael.lee.ther...@gmail.com> 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 < > michael.lee.ther...@gmail.com> 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 < > francois.remy....@outlook.com> 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: es-discuss@mozilla.org > >> >>>>> 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 < > t...@thenewobjective.com> 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 <es-discuss-boun...@mozilla.org> On Behalf Of > Laurie Harper > >> >>>>> Sent: Friday, June 5, 2020 12:21 AM > >> >>>>> To: es-discuss@mozilla.org > >> >>>>> 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 > >> >>>>> es-discuss@mozilla.org > >> >>>>> https://mail.mozilla.org/listinfo/es-discuss > >> >>>>> > >> >>>>> > >> >>> > >> >>> _______________________________________________ > >> >>> es-discuss mailing list > >> >>> es-discuss@mozilla.org > >> >>> https://mail.mozilla.org/listinfo/es-discuss > >> > > >> > _______________________________________________ > >> > es-discuss mailing list > >> > es-discuss@mozilla.org > >> > https://mail.mozilla.org/listinfo/es-discuss > >> _______________________________________________ > >> es-discuss mailing list > >> es-discuss@mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss >
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss