带有getter和setter的JavaScript类导致RangeError:超过最大调用堆栈大小
我目前正在试验ECMA6类。 我当前的课程如下所示带有getter和setter的JavaScript类导致RangeError:超过最大调用堆栈大小,javascript,node.js,node-mysql,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 P
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库有什么关系?为什么错误会在同一行中多次出现?我只叫它一次。你的“现金”设定者叫“现金”设定者,它叫“现金”设定者,它叫“现金”设定者
在setter中使用自己的名称访问属性setter会创建一个无限递归函数调用。cash表示getter/setter,而cash是“private”属性
set cash(value) { // line 19
this._cash = value; // line 20
}
请看一个清晰的示例。您正在递归调用getter
它遵循一种可能的替代方案:
class Player {
constructor(id) {
this.id = id;
this._cash = 350;
}
get cash() {
return this._cash;
}
set cash(value) {
this._cash = value;
}
};
另一个使用对象。定义属性:
class Player {
constructor(id) {
this.id = id;
var _cash = 350;
Object.defineProperty(this, 'cash', {
get: function() {
return _cash;
}
set: function(v) {
_cash = v;
}
});
}
};
Get&setes6类为上的getter和setter带来了一种新语法
对象属性。Get和set允许我们在读卡器上运行代码
书写财产。ES5也有接球手和二传手,但不是
由于旧的IE浏览器而被广泛使用。ES5的能手和二传手做到了
没有ES6带给我们的那么好的语法。因此,让我们创建一个get
并设置为我们的名称属性
set cash(value) { // line 19
this._cash = value; // line 20
}
资料来源:
示例:
// 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'
我知道我迟到了,但我想我可以在这里澄清一两点:
首先是隐私问题,这是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.cash获取它,并使用player1.cash=newCash进行设置;它抛出错误是因为getter和setter被递归调用,正如其他人提到的
但是,如果您只是将该属性重命名为this.\u cash,则必须了解该不是私有属性。如果您尝试访问player1.\u cash,您将以与player1.cash相同的方式访问属性值
那么,我们如何实现隐私权呢?
使用ES6/ES2015有两种主要方法:使用新的基本类型或使用。我不会详细介绍该语言的这两个新特性,但我将展示在本例中如何实现这一点
使用符号:
使用弱贴图
重要的
虽然符号的语法更好,但它需要浏览器的本机支持才能实际工作。您可以使用transpiler编写它,但在后台,它将模仿旧的ES5标准。对WeakMaps的本机支持更好,另一方面,此功能只与GC和对象属性的可枚举选项配合使用。因此,最终,这是您的选择。我对ECMA6类了解不够,但您似乎在递归调用setter。递归调用意味着什么?它意味着它在调用自己。尝试将setter方法重命名为cash以外的其他方法。重命名“内部”变量可能重复。我把this.cash
改为this.playerCash
。谢谢大家。@Cludch没问题。你应该养成不重复使用名称的习惯,或者如果你真的想使用这个名称,在前面加上“get”或“set”,例如“getCash”或“setCash”。真的很烦人。如果我这样做,当我想序列化/反序列化对象时会发生什么?我相信它会被序列化为“{u-cash:350}”
,这对于通过网络发送并不理想。您必须编写一个自定义的toString()
函数来处理此问题。
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;
}
}