ES6 代理类,访问私有属性(无法从类未声明的对象读取私有成员 #hidden)



我在玩代理对象、类和私有属性。 并遇到了以下错误消息:

/home/marc/projects/playground/pipeline/clsss.js:14
this.#hidden = !this.#hidden;
^
TypeError: Cannot read private member #hidden from an object whose class did not declare it
at Proxy.toggle (/home/marc/projects/playground/pipeline/clsss.js:14:30)
at Object.<anonymous> (/home/marc/projects/playground/pipeline/clsss.js:37:19)
at Module._compile (internal/modules/cjs/loader.js:1118:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1138:10)
at Module.load (internal/modules/cjs/loader.js:982:32)
at Function.Module._load (internal/modules/cjs/loader.js:875:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47

要重现的代码:

class Parent {
#hidden;
constructor() {
this.#hidden = false;
}
get hidden() {
return this.#hidden;
}
toggle() {
this.#hidden = !this.#hidden;
console.log("Changed", this.#hidden)
return this.#hidden;
}
}

const p = new Parent();
const proxy = new Proxy(p, {
get: (target, prop, receiver) => {
return target[prop];
}
});
console.log(p.toggle())
console.log(proxy.toggle())  // this is the problem
console.log(p.toggle())

有没有办法处理代理类实例上的私有属性?

为什么这不适用于代理?

感谢您的任何提示/答案。

编辑:在github上发现了一个相关问题:https://github.com/tc39/proposal-class-fields/issues/106 我发现的一个快速技巧是使用:

const proxy = new Proxy(..., {
get: (target, prop, receiver) => {
// bind context to original object
if (target[prop] instanceof Function) {
return target[prop].bind(p);
}
return target[prop];
}
});

但这似乎非常不干净/错误。

如果这是所需的行为,则可以在构造函数上绑定该方法:

constructor() {
this.#hidden = false;
this.toggle = this.toggle.bind(this);
}

演示:

class Parent {
#hidden;
constructor() {
this.#hidden = false;
this.toggle = this.toggle.bind(this);
}
get hidden() {
return this.#hidden;
}
toggle() {
this.#hidden = !this.#hidden;
console.log("Changed", this.#hidden)
return this.#hidden;
}
}

const p = new Parent();
const proxy = new Proxy(p, {
get: (target, prop, receiver) => {
return target[prop];
}
});
console.log(p.toggle())
console.log(proxy.toggle())  // this is the problem
console.log(p.toggle())

否则,您可以代理类本身:

class Parent {
#hidden;
constructor() {
this.#hidden = false;
}
get hidden() {
return this.#hidden;
}
toggle() {
this.#hidden = !this.#hidden;
//console.log("Changed", this.#hidden)
return this.#hidden;
}
}

const p = new Parent();
const ParentProxy = new Proxy(Parent, {
get(target, prop, receiver) {
return target[prop];
}
});
const p2 = new ParentProxy();
console.log('p toggle:', p.toggle());
console.log('p2 toggle:', p2.toggle());  //
//console.log(proxy.toggle())  // this is the problem
console.log('p toggle:', p.toggle());
console.log('p2 toggle:', p2.toggle());

这是不可能的,请阅读它说的错误消息Cannot read private member #hidden from an object whose class did not declare it一旦您创建了代理并尝试从中访问某些内容,就不会与您包装的原始类相同。

更新:您可以在此处阅读有关私有字段及其工作原理的更多信息 https://developer.cdn.mozilla.net/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields

Proxy对象提供对targetprop的直接访问,因此您可以像直接从实例访问一样简单地访问私有。

我的方法就像;

class Parent {
#hidden;
constructor() {
this.#hidden = false;
}
get hidden() {
return this.#hidden;
}
toggle() {
this.#hidden = !this.#hidden;
console.log("Changed", this.#hidden)
return this.#hidden;
}
}

var p = new Parent();
var proxy = new Proxy(p,{get: (target,prop,receiver) => _ => target[prop]()});
console.log(p.toggle())
console.log(proxy.toggle())  // this is the problem
console.log(p.toggle())

在思考的第二个层面上,这实际上可能会变得更好,例如;

class Parent {
#hidden;
constructor() {
this.#hidden = false;
}
get hidden() {
return this.#hidden;
}
toggle() {
this.#hidden = !this.#hidden;
console.log("Changed", this.#hidden)
return this.#hidden;
}
}

var p = new Parent();
var proxy = new Proxy(p,{get: (target,prop,receiver) => target[prop].bind(target)});
console.log(p.toggle())
console.log(proxy.toggle())  // this is the problem
console.log(p.toggle());

这清楚地告诉您Proxy对象不是实例本身。您应该显式bind传递的函数属性(或原型方法),这些属性可以访问要targetClass的">私有"属性,以便使它们正常运行。

最新更新