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

时间:2015-07-17 20:52:41

标签: 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
  }
};

当我现在通过调用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

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

5 个答案:

答案 0 :(得分:25)

你的"现金"塞特打电话给"现金"塞特,称之为"现金"塞特,称之为"现金"设定器...

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

答案 1 :(得分:15)

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

首先,存在隐私的问题,这是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();

在这种情况下, this.cash是一个公共属性,所以你真的不需要getter和setter方法来处理它,因为你可以用 player1来获取它。现金并使用 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;
   }

}

使用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;
   }

}

重要

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

答案 2 :(得分:4)

现金代表getter / setter,_cash是私人'属性。

  set cash(value) { // line 19
      this._cash = value; // line 20
  }

请查看this page以获得明确的示例。

答案 3 :(得分:4)

你正在递归地召唤你的吸气鬼。

它遵循一个可能的替代方案:

Object.defineProperty

使用class Player { constructor(id) { this.id = id; var _cash = 350; Object.defineProperty(this, 'cash', { get: function() { return _cash; } set: function(v) { _cash = v; } }); } }; 的另一个人:

$(document).ready(function() {
  var aboveHeight = 205;
  $('.sticknav').addClass('unfixed');

  $(window).scroll(function(){
    if ($(window).scrollTop() > aboveHeight &&  $('.sticknav').hasClass('unfixed')){
      $('.sticknav').addClass('fixed').removeClass('unfixed').css('top','0').next().css('padding-top','60px');
    } else if($(window).scrollTop() < aboveHeight  &&  $('.sticknav').hasClass('fixed')){
      $('.sticknav').addClass('unfixed').removeClass('fixed').next().css('padding-top','0');
    }
  });
});

答案 4 :(得分:0)

  

获取&amp;设置ES6类为getter和setter带来了新的语法   对象属性。获取和设置允许我们在阅读或运行代码   写一个财产。 ES5也有吸气剂和二传手,但事实并非如此   由于旧的IE浏览器而广泛使用。 ES5 getter和setter做到了   没有ES6带给我们的语法那么好。所以让我们创建一个get   并为我们的名称属性设置。

     

来源:JavaScript ES6 Class Syntax

示例

// ES6 get and set
class Person {
    constructor(name) {
        this._name = name;
    }

    get name() {
        return this._name.toUpperCase();
    }

    set name(newName) {
        this._name = newName;   // validation could be checked here such as only allowing non numerical values
    }

    walk() {
        console.log(this._name + ' is walking.');
    }
}

let bob = new Person('Bob');
console.log(bob.name);  // Outputs 'BOB'