You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重定义类方法时无法访问私有成员的问题及解决咨询

问题:类私有字段#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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 03:40:38