类型错误:无法访问/设置私有字段或方法:对象不是正确的类
JavaScript 异常“无法访问私有字段或方法:对象不是正确的类 "or" 无法设置私有字段:当在未定义此 私有属性 的对象上获取或设置私有字段或方法时,会发生“对象不是正确的类”。
¥The JavaScript exception "can't access private field or method: object is not the right class" or "can't set private field: object is not the right class" occurs when a private field or method is get or set on an object that does not have this private property defined.
信息
¥Message
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)
错误类型
什么地方出了错?
¥What went wrong?
你正在尝试获取或设置对象上的私有字段或方法,但该对象不包含此私有属性。私有实例属性只能在声明它们的类(包括其子类)的实例上访问;私有静态属性只能在声明它们的类本身上访问,而不能在子类上访问。
¥You are trying to get or set a private field or method on an object, but that object does not contain this private property. Private instance properties can only be accessed on instances of the class (including its subclasses) that declares them; private static properties can only be accessed on the class itself that declares them, and not on subclasses.
当私有名称存在于类范围内但其访问的对象无效时,会发生此错误,如果私有名称不存在,你将获得 语法错误。
¥This error occurs when the private name exists in the class scope but the object it's accessed on is invalid, If the private name does not exist, you will get a syntax error instead.
示例
不匹配的静态/实例字段
¥Mismatched static/instance fields
你可能已将该字段声明为静态字段,但正在尝试在实例上访问它,反之亦然。
¥You may have declared the field as a static field, but are trying to access it on an instance, or vice versa.
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
要修复此问题,请将字段更改为实例字段,或在类本身上访问该字段,或声明另一个实例上的字段。请注意,私有命名空间在静态和实例属性之间共享,因此你不能拥有具有相同名称的静态和实例私有属性。
¥To fix this, either change the field to be an instance field, or access the field on the class itself, or declare another field on the instance. Note that the private namespace is shared between static and instance properties, so you cannot have a static and instance private property with the same name.
class MyClass {
#x = 0;
doSomething() {
console.log(this.#x);
}
}
class MyClass2 {
static #x = 0;
doSomething() {
console.log(MyClass2.#x);
}
}
使用了错误的对象
¥Wrong object used
也许你有一个访问 this.#x
的方法,但它使用另一个 this
值调用。
¥Perhaps you have a method that access this.#x
, but it is called with another this
value.
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 函数,因此私有字段不可访问。要解决此问题,你可以将方法绑定到对象,或使用箭头函数,以确保使用正确的 this
值调用 replacer.func
。
¥This is because JSON.stringify()
calls the replacer function with the object containing value
as this
, so the private field is not accessible. To fix this, you can bind the method to the object, or use an arrow function, to ensure that replacer.func
is called with the correct this
value.
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:无法将未定义转换为对象)。仅当使用不同的对象作为 this
调用该方法时,才会发生此错误,无论是使用 call()
或 apply()
,还是通过将方法作为回调传递给使用不同的 this
值调用它的函数。
¥Most of the time, if you accidentally unbound a method, the method would be called with undefined
as this
, which would result in a different error (TypeError: can't convert undefined to object). This error only occurs when the method is called with a different object as this
, either by using call()
or apply()
, or by passing the method as a callback to a function that calls it with a different this
value.
如果你不确定对象是否包含私有属性,如以下代码所示:
¥If you don't know for sure that the object will contain the private property, as in the following code:
class MyClass {
#x = 0;
static doSomething(obj) {
console.log(obj.#x); // Throws if obj is not an instance of MyClass
}
}
你可以先使用 in
运算符执行品牌检查。
¥You can use the in
operator to perform a branded check first.
class MyClass {
#x = 0;
static doSomething(obj) {
if (!(#x in obj)) {
return;
}
console.log(obj.#x);
}
}
访问子类上的静态属性
¥Accessing static properties on subclasses
如果你有 私有静态属性,你只能在声明它的类上访问它,而不能在子类上访问它。
¥If you have a private static property, you can only access it on the class that declares it, not on subclasses.
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
访问私有静态属性。相反,始终明确指定类的名称。
¥To fix this, never access private static properties through this
. Instead, always explicitly specify the class's name.
class MyClass {
static #x = 0;
doSomething() {
console.log(MyClass.#x);
}
}
访问另一个类上的同名私有属性
¥Accessing same-name private properties on another class
与普通字符串或符号属性不同,私有名称不会在类之间共享。如果两个类中都有同名的私有属性,它们仍然不是同一个属性,你无法从另一个类访问一个类的私有属性。
¥Unlike normal string or symbol properties, private names are not shared between classes. If you have a private property with the same name in two classes, they are still not the same property, and you cannot access one class's private property from another class.
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
向不相关的对象添加私有属性
¥Adding private properties to unrelated objects
你不能动态地将私有属性添加到不相关的对象。
¥You cannot dynamically add private properties to unrelated objects.
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
。
¥If you really want to do this, consider the return override trick. However, in general, you would probably want to use a WeakMap
instead.
class MyClass {
static #objToX = new WeakMap();
static stamp(obj) {
MyClass.#objToX.set(obj, 1);
}
}
MyClass.stamp({});