重定义类方法时无法访问私有成员的问题及解决咨询
问题:类私有字段
#secret在重定义方法后无法访问 当使用#定义私有成员后,重新定义使用该私有成员的类成员时,会出现无法访问该私有成员的情况:
JavaScript 示例代码
class Foo { #secret = "Keyboard Cat"; method() { console.log(this.#secret); } } const target = Foo.prototype; const key = "method"; const desc = Object.getOwnPropertyDescriptor(target, key); const og = desc.value; desc.value = function (...args) { return og.apply(target, args); }; Object.defineProperty(target, key, desc); new Foo().method();
报错信息
Uncaught TypeError: Cannot read private member #secret from an object whose class did not declare it
为何会出现这种情况?只是对原方法进行了包装而已。注:该示例是TypeScript装饰器使用场景的简化版本。如何在仍能重定义并修改方法的前提下解决此问题?
TypeScript 装饰器场景示例
const Curse: MethodDecorator = (target, _, desc) => { const og = desc.value as Function; desc.value = function (...args: any[]) { return og.apply(target, args); } as any; return desc; }; class Foo { #secret = "Keyboard Cat"; @Curse method() { console.log(this.#secret); } } new Foo().method();
原因分析
JavaScript的私有字段#secret是严格绑定到类实例和原始方法的词法作用域的,它的访问权限不是基于this的指向,而是看当前执行代码是否属于定义该私有字段的类的词法环境。
包装方法时调用og.apply(target, args),这里的target是Foo.prototype而非类的实例。原始方法og执行时,this指向Foo.prototype,但Foo.prototype并没有声明#secret私有字段,因此会抛出权限错误。
解决方案
核心是确保原始方法执行时,this指向类的实例而非prototype。修改包装函数,用当前调用的this(即实例)来调用原始方法:
修复后的JavaScript代码
class Foo { #secret = "Keyboard Cat"; method() { console.log(this.#secret); } } const target = Foo.prototype; const key = "method"; const desc = Object.getOwnPropertyDescriptor(target, key); const og = desc.value; // 使用当前调用的this(实例)执行原始方法 desc.value = function (...args) { return og.apply(this, args); }; Object.defineProperty(target, key, desc); new Foo().method(); // 输出 "Keyboard Cat"
修复后的TypeScript装饰器代码
const Curse: MethodDecorator = (target, _, desc) => { const og = desc.value as Function; // 使用当前调用的this(实例)执行原始方法 desc.value = function (...args: any[]) { return og.apply(this, args); } as any; return desc; }; class Foo { #secret = "Keyboard Cat"; @Curse method() { console.log(this.#secret); } } new Foo().method(); // 输出 "Keyboard Cat"
关键说明
- 包装函数中的
this在调用时会自动绑定到类实例(new Foo().method()调用时,this指向实例)。 - 原始方法
og通过apply(this, args)执行时,this指向声明了#secret的类实例,因此可以正常访问私有字段。 - 这种方式既保留了方法包装的能力,又遵守了私有字段的访问规则。
内容的提问来源于stack exchange,提问作者k-tten
相关产品推荐
相关产品推荐

