为什么开发人员在JavaScript中使用get和set时会使用“ _”?

时间:2019-08-03 09:00:21

标签: javascript oop getter-setter

我知道使用下划线只是在JavaScript中定义私有变量的约定。但是我遇到了一个[在使用类时]用例,其中使用_似乎必须使代码正常工作!我的问题是_get在引擎盖下如何使用set

以下代码抛出错误:

  

RangeError:超出了最大调用堆栈大小

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);

3 个答案:

答案 0 :(得分:6)

您的第一个代码片段使用的getter / setter名称与您尝试分配给该属性的名称相同。因此,在构造函数中,当您这样做

this.name = name;

您正在调用name设置器,它会执行以下操作:

this.name = val;

再次调用name setter,该setter递归调用自己,直到堆栈溢出为止。

为数据的 actual property 使用不同的变量名(与getter / setter相比)可以使代码按预期工作。它不必带有下划线前缀-除getter / setter所使用的相同名称外,几乎所有其他都可以使用。

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);

通常,属性名称前的_表示该属性是私有的,并且只有类本身可以访问它,但这不能保证-类的用户仍然可以如果愿意,请参考user._name。如果要为每个实例提供 actual 私有数据,则应在带有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);

答案 1 :(得分:4)

只需从逻辑上看这段代码:

get name() {
    return this.name
}

您阅读了object.name。要返回值,get name()的getter读取this.name,然后解析为get name()。现在,欢迎来到无限循环。

因此,您需要一个与getter名称不同的变量名称(用于存储name的实际内容)。那将是一个私有变量,在这些情况下,在其前面加下划线已成为惯例。

答案 2 :(得分:2)

_缀通常用于私有财产。

当您希望能够控制更新属性的方式和时间或向这些操作添加副作用时,除了使用getter和/或setter之外,还使用私有属性。

您还应该在班级中有一个私有财产声明

class User {
  private _name; // <-- here

  constructor(name) {
    this.name = name;
  }

  get name() {
    return this._name;
  }

  set name(val) {
    this._name = val;
  }
}