TypeError: 无法访问/设置私有字段或方法:对象不是正确的类
当在未定义此私有属性的对象上获取或设置私有字段或方法时,会出现JavaScript异常“无法访问私有字段或方法:对象不是正确的类”或“无法设置私有字段:对象不是正确的类”。
消息
TypeError: Cannot read private member #x from an object whose class did not declare it (V8-based) TypeError: Cannot write private member #x to an object whose class did not declare it (V8-based) TypeError: can't access private field or method: object is not the right class (Firefox) TypeError: can't set private field: object is not the right class (Firefox) TypeError: Cannot access invalid private field (evaluating 'this.#x') (Safari)
错误类型
出了什么问题?
您正在尝试获取或设置对象上的私有字段或方法,但该对象不包含此私有属性。私有实例属性只能在声明它们的类的实例(包括其子类)上访问;私有静态属性只能在声明它们的类本身(而不是子类)上访问。
当私有名称存在于类范围内但访问它的对象无效时,就会发生此错误。如果私有名称不存在,则会改为出现语法错误。
示例
静态/实例字段不匹配
您可能已将字段声明为静态字段,但尝试在实例上访问它,反之亦然。
class MyClass {
static #x = 0;
doSomething() {
console.log(this.#x);
}
}
const obj = new MyClass();
obj.doSomething();
// TypeError: can't access private field: object is not the right class
要解决此问题,请更改字段为实例字段,或在类本身访问该字段,或在实例上声明另一个字段。请注意,私有命名空间在静态和实例属性之间共享,因此您不能使用相同名称的静态和实例私有属性。
class MyClass {
#x = 0;
doSomething() {
console.log(this.#x);
}
}
class MyClass2 {
static #x = 0;
doSomething() {
console.log(MyClass2.#x);
}
}
使用了错误的对象
也许您有一个访问this.#x
的方法,但它使用另一个this
值调用。
class JSONReplacer {
#count = 0;
func(key, value) {
if (typeof value === "object") {
this.#count++;
}
return value;
}
}
JSON.stringify({ a: 1, b: { c: 2 } }, new JSONReplacer().func);
// TypeError: can't access private field: object is not the right class
这是因为JSON.stringify()
使用包含value
作为this
的对象调用replacer函数,因此无法访问私有字段。要解决此问题,您可以将方法绑定到对象,或使用箭头函数,以确保replacer.func
使用正确的this
值调用。
const replacer = new JSONReplacer();
JSON.stringify({ a: 1, b: { c: 2 } }, replacer.func.bind(replacer));
JSON.stringify({ a: 1, b: { c: 2 } }, (...args) => replacer.func(...args));
大多数情况下,如果您意外地解绑了一个方法,则该方法将使用undefined
作为this
调用,这将导致不同的错误(TypeError: 无法将undefined转换为对象)。此错误仅在使用call()
或apply()
调用方法,或者将方法作为回调传递给使用其他this
值调用它的函数时发生。
如果您不确定对象是否包含私有属性,如下面的代码所示
class MyClass {
#x = 0;
static doSomething(obj) {
console.log(obj.#x); // Throws if obj is not an instance of MyClass
}
}
您可以使用in
运算符首先执行品牌检查。
class MyClass {
#x = 0;
static doSomething(obj) {
if (!(#x in obj)) {
return;
}
console.log(obj.#x);
}
}
在子类上访问静态属性
如果您有一个私有静态属性,则只能在声明它的类上访问它,而不能在子类上访问它。
class MyClass {
static #x = 0;
doSomething() {
console.log(this.#x);
}
}
class MySubClass extends MyClass {}
MySubClass.doSomething();
// TypeError: can't access private field: object is not the right class
要解决此问题,切勿通过this
访问私有静态属性。而是始终显式指定类的名称。
class MyClass {
static #x = 0;
doSomething() {
console.log(MyClass.#x);
}
}
在另一个类上访问同名私有属性
与普通字符串或符号属性不同,私有名称不会在类之间共享。如果两个类中都有一个同名的私有属性,它们仍然不是同一个属性,并且您无法从另一个类访问一个类的私有属性。
class MyClass {
#x = 0;
}
class MyOtherClass {
#x = 1;
doSomething(o) {
console.log(o.#x);
}
}
const obj = new MyClass();
new MyOtherClass().doSomething(obj);
// TypeError: can't access private field: object is not the right class
向不相关的对象添加私有属性
您无法动态添加不相关的对象的私有属性。
class MyClass {
#x = 0;
static stamp(obj) {
obj.#x = 1;
}
}
MyClass.stamp({});
// TypeError: can't set private field: object is not the right class
如果您确实需要这样做,请考虑返回覆盖技巧。但是,通常,您可能希望改用WeakMap
。
class MyClass {
static #objToX = new WeakMap();
static stamp(obj) {
MyClass.#objToX.set(obj, 1);
}
}
MyClass.stamp({});