我知道使用下划线只是 JavaScript 中定义私有(private)变量的约定。但是我遇到了一个用例 [在使用类时],其中似乎必须使用 _
才能使代码正常工作!我的问题是 _
是如何被 get
和 set
使用的。
下面的代码会抛出一个错误:
RangeError: Maximum call stack size exceeded
class User {
constructor(name) {
this.name = name;
}
get name() {
return this.name;
}
set name(val) {
this.name = val;
}
}
let user = new User("Jhon");
console.log(user.name);
现在,如果我使用 _
,代码就可以工作了!
class User {
constructor(name) {
this.name = name;
}
get name() {
return this._name; // Added "_" here
}
set name(val) {
this._name = val; // Added "_" here
}
}
let user = new User("Jhon");
console.log(user.name);
您的第一个代码段使用与您尝试分配给的属性相同的 getter/setter 名称。所以,在构造函数中,当你这样做的时候
this.name = name;
您正在调用 name
setter,它会:
this.name = val;
再次调用 name
setter ,它递归调用自身直到堆栈溢出。
为存储数据的实际属性 使用不同的变量名称(与 getter/setter 相比)允许代码按预期工作。它不必以下划线作为前缀 - 除了 getters/setters 使用的相同名称之外,几乎任何都可以。
class User {
constructor(name) {
this.name = name;
}
get name() {
return this.actualProperty;
}
set name(val) {
this.actualProperty = val;
}
}
let user = new User("Jhon");
console.log(user.name);
属性名称前的 _
通常表示该属性是私有(private)的,只有类本身才能访问它,但这并不能保证 - 类的用户是如果他们愿意,仍然可以自由引用 user._name
。如果您想要每个实例的实际私有(private)数据,您应该在闭包中定义类,其中包含一个包含私有(private)数据的 WeakMap:
const User = (() => {
const data = new WeakMap();
return class User {
constructor(name) {
this.name = name;
}
get name() {
return data.get(this);
}
set name(val) {
data.set(this, val);
}
}
})();
let user = new User("Jhon");
console.log(user.name);