为什么开发者在JavaScript中使用get和set时使用“_”?
Why do developers use "_" while using get and set in JavaScript?
我知道在JavaScript中使用下划线只是定义私有变量的约定。但是我遇到了一个用例 [在使用 class] 时似乎必须使用 _
才能使代码正常工作!我的问题是 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,递归调用自身直到堆栈溢出。
为 实际 属性 数据存储使用不同的变量名称(与 getters/setters 相比)允许代码作为故意的。它不必以下划线作为前缀 - 除了 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);
属性 名称前的 _
通常表示 属性 是私有的,只有 class 本身可以访问它,但这并不能保证 - class 的用户仍然可以根据需要自由参考 user._name
。如果你想要每个实例的 actual 私有数据,你应该在一个包含私有数据的 WeakMap 的闭包中定义 class:
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);
逻辑上看这段代码:
get name() {
return this.name
}
您阅读了object.name
。对于 return 一个值,get name()
getter 读取 this.name
,然后解析为 get name()
。现在,欢迎来到无限循环。
因此,您需要一个不同于getter 的名称的单独变量名称(用于存储name
的实际内容)。那将是一个私有变量,在这些情况下,在前面加上下划线已成为一种惯例。
_
词缀通常用于私有属性。
当您希望能够控制更新 属性 的方式和时间,或者为这些操作添加副作用时,除了 getter and/or setter 之外,您还可以使用私有属性。
您还应该在 class
中有一个私有的 属性 声明
class User {
private _name; // <-- here
constructor(name) {
this.name = name;
}
get name() {
return this._name;
}
set name(val) {
this._name = val;
}
}
我知道在JavaScript中使用下划线只是定义私有变量的约定。但是我遇到了一个用例 [在使用 class] 时似乎必须使用 _
才能使代码正常工作!我的问题是 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,递归调用自身直到堆栈溢出。
为 实际 属性 数据存储使用不同的变量名称(与 getters/setters 相比)允许代码作为故意的。它不必以下划线作为前缀 - 除了 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);
属性 名称前的 _
通常表示 属性 是私有的,只有 class 本身可以访问它,但这并不能保证 - class 的用户仍然可以根据需要自由参考 user._name
。如果你想要每个实例的 actual 私有数据,你应该在一个包含私有数据的 WeakMap 的闭包中定义 class:
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);
逻辑上看这段代码:
get name() {
return this.name
}
您阅读了object.name
。对于 return 一个值,get name()
getter 读取 this.name
,然后解析为 get name()
。现在,欢迎来到无限循环。
因此,您需要一个不同于getter 的名称的单独变量名称(用于存储name
的实际内容)。那将是一个私有变量,在这些情况下,在前面加上下划线已成为一种惯例。
_
词缀通常用于私有属性。
当您希望能够控制更新 属性 的方式和时间,或者为这些操作添加副作用时,除了 getter and/or setter 之外,您还可以使用私有属性。
您还应该在 class
中有一个私有的 属性 声明class User {
private _name; // <-- here
constructor(name) {
this.name = name;
}
get name() {
return this._name;
}
set name(val) {
this._name = val;
}
}