为什么我的javascript getter/setter需要下划线?

为什么我的javascript getter/setter需要下划线?,javascript,Javascript,对a执行[[Get]]或[[Put]]操作会抛出一个RangeError,指出超过了最大调用堆栈大小,指向getter中的和setter中的= let someObject = { get a() { return this.a; }, set a(val) { this.a = val; } } someObject.a; // Error someObject.a = 5; // Error 但是,如果getter和setter中的属性加下划线,则它们

a
执行[[Get]]或[[Put]]操作会抛出一个RangeError,指出
超过了最大调用堆栈大小
,指向getter中的
和setter中的
=

let someObject = {
  get a() {
    return this.a;
  },
  set a(val) {
    this.a = val;
  }
}

someObject.a;  // Error
someObject.a = 5;  // Error
但是,如果getter和setter中的属性加下划线,则它们可以工作:

let someObject = {
  get a() {
    return this._a_;
  },
  set a(val) {
    this._a_ = val;
  }
}
我已经在Chrome的节点环境和v10引擎中对此进行了测试,同样的情况也发生了


如此混乱。发送帮助。

一旦使用某个属性的setter定义了对象,该setter始终用于设置属性值,即使在setter本身内部也是如此!如果您试图在setter中使用简单赋值设置属性,JavaScript将再次调用setter,您将得到无限递归

在第二个“秘密名称”中使用一个特殊的前导字符,如“u”,这是一种常见的约定。但是,该属性仍然在外部可见(尽管可以使其不可枚举)。在较新的JavaScript环境中可用的另一种方法是使用符号实例而不是属性名。符号实例保证您的内部属性标识符永远不会与应用程序中其他来源的其他属性名称冲突

因此:


该代码使用闭包为实际属性键创建一个私有变量,该属性键外部看起来像一个名为“a”的属性。任何其他代码都不可能意外地“踩到”setter/getter对使用的私有实际属性,因为这就是符号的用途。

您需要一个与getter/setter名称不同的变量。最常见的方法是在变量前面加一个
\uuuu

否则,如果不这样做,将有一个对getter/setter的无休止的调用循环

class A {
    constructor() {
        this._a = '';
    }

    get a() {
        // If we don't call it like this
        // We will be calling the getter again
        // Which in return will call itself again
        return this._a
    }
}

因为通过执行
返回这个.a
您正在访问
a
属性,它触发getter函数,它访问
a
属性,它触发getter函数,它访问
a
属性,它触发getter函数。。。无止境的循环

setter也是如此。

对象上只能有一个
a
属性
.a
不能同时引用属性和setter。
class A {
    constructor() {
        this._a = '';
    }

    get a() {
        // If we don't call it like this
        // We will be calling the getter again
        // Which in return will call itself again
        return this._a
    }
}