带有getter和setter的JavaScript类导致RangeError:超出了最大调用堆栈大小

Clu*_*dch 23 javascript node.js node-mysql

我目前正在试验ECMA6课程.我目前的课程如下所示

class Player {
  constructor(id) {
    this.id = id;
    this.cash = 350;
  }

  get cash() {
    return this.cash;
  }

  set cash(value) { // line 19
    this.cash = value; // line 20
  }
};
Run Code Online (Sandbox Code Playgroud)

当我现在通过调用创建一个新的对象时,let playerObject = new Player(1);我收到以下错误

...\node_modules\mysql\lib\protocol\Parser.js:82
        throw err;
              ^
RangeError: Maximum call stack size exceeded
    at Player.cash (player.js:19:11)
    at Player.cash (player.js:20:15)
    at Player.cash (player.js:20:15)
    at Player.cash (player.js:20:15)
    at Player.cash (player.js:20:15)
    at Player.cash (player.js:20:15)
    at Player.cash (player.js:20:15)
    at Player.cash (player.js:20:15)
    at Player.cash (player.js:20:15)
    at Player.cash (player.js:20:15)
Press enter to exit
Run Code Online (Sandbox Code Playgroud)

这与mysql库有什么关系?为什么错误在同一行中多次?我只打电话一次.

Gre*_*rdt 26

你的"现金"制定者称为"现金"制定者,称为"现金"制定者,称为"现金"制定者......

在setter中通过自己的名称访问属性setter会创建一个无限的递归函数调用.

  • 重命名"内部"变量.我将`this.cash`改为`this.playerCash`.谢谢你们. (3认同)

Mat*_*zol 17

我知道我迟到了,但我想我可以在这里澄清一两点:

首先,存在隐私问题,这是JavaScript社区中的长期讨论.

class Player {
   constructor(id) {
      this.cash = 350; // this._cash, alternatively
   }

   get cash() {
      return this.cash;
   }

   set cash(value) {
      this.cash = value;
   }
};

let player1 = new Player();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,this.cash是一个公共属性,所以你真的不需要getter和setter方法来处理它,因为你可以用player1.cash来获取它并用player1.cash = newCash设置它; 它正在抛出错误,因为正如其他人所提到的那样,递归地调用getter和setter.

但是,如果您只是将属性重命名为this._cash,则必须了解这不是私有财产.如果您尝试访问player1._cash,则可以使用与player1.cash相同的方式访问属性值.

那么,我们如何才能真正实现隐私?

使用ES6/ES2015有两种主要方法:使用新的原始类型Symbol或使用WeakMaps.我不会详细介绍该语言的这两个新功能,但我将展示如何在这种情况下实现这一功能.

使用符号:

const CASH = Symbol();

class Player {

   constructor () {
      this[CASH] = 350;
   }

   get cash(){
      return this[CASH];
   }

   set cash(cash) {
      this[CASH] = cash;
   }

}
Run Code Online (Sandbox Code Playgroud)

使用WeakMaps

let map =  new WeakMap();

class Player {

   constructor () {
      map.set(this, {
         cash: 350
      });    
   }

   get cash(){
      return map.get(this).cash;
   }

   set cash(cash) {
      map.get(this).cash = cash;
   }

}
Run Code Online (Sandbox Code Playgroud)

重要

虽然符号的语法更好,但它需要浏览器的本机支持才能实际工作.您可以使用转换器编写它,但在引擎盖下,它会将其模拟为旧的ES5标准.对WeakMaps的本机支持更好,另一方面,此功能只使用GC和对象属性的可枚举选项.所以,最后,这是你的选择.


hta*_*che 5

cash 代表 getter/setter,_cash 是“私有”属性。

  set cash(value) { // line 19
      this._cash = value; // line 20
  }
Run Code Online (Sandbox Code Playgroud)

查看此页面以获取清晰的示例。