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

我目前正在试验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);创build一个新的对象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库有什么关系? 为什么错误是在同一行多次? 我只是调用一次。

你的“现金”二传手调用“现金”二传手,它调用“现金”二传手,它调用“现金”二传手…

在setter中通过自己的名字访问属性setter会创build一个无限的recursion函数调用。

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

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

在这种情况下,这个.cash是一个公共属性 ,所以你并不需要一个getter和一个setter方法来处理它,因为你可以用player1.cash得到它,并用player1.cash = newCash来设置它。 它正在抛出错误,因为getter和setter被recursion调用,正如其他人所说的那样。

但是,如果您只是将属性重命名为this._cash ,则必须明白这不是私有属性 。 如果您尝试访问player1._cash ,则可以像使用player1.cash一样访问属性值。

那么, 我们如何才能保护隐私呢?

使用ES6 / ES2015有两种主要的方法:使用新的原始typesSymbol或使用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; } } 

重要

虽然符号的语法更好,但它需要本地支持浏览器才能正常工作。 你可以用transpiler写,但是在引擎盖下,它会嘲弄它到旧的ES5标准。 WeakMaps的本地支持更好,另一方面,这个function只是使用GC和对象属性的可枚举选项。 所以,最后,这是你的select。

现金代表着获得者/制定者,_cash是“私人”财产。

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

看看这个页面的一个清晰的例子。

你正在recursion地调用你的getter。

它有一个可能的select:

 class Player { constructor(id) { this.id = id; this._cash = 350; } get cash() { return this._cash; } set cash(value) { this._cash = value; } }; 

另一个使用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; } }); } }; 

Get&Set ES6类为对象属性的getter和setter提供了一个新的语法。 获取和设置允许我们在读取或写入属性时运行代码。 ES5也有getter和setter,但由于旧的IE浏览器没有被广泛使用。 ES5 getters和setter没有ES6给我们带来的那么好的语法。 所以让我们创build一个get并为我们的name属性设置。

来源: JavaScript ES6类语法

例如

 // 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'