JavaScript classes with getter and setter cause RangeError: Maximum call stack size exceeded
JavaScript classes with getter and setter cause RangeError: Maximum call stack size exceeded
我目前正在试验 ECMA6 classes。
我当前的 class 如下所示
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 库有什么关系?为什么错误在同一行中出现多次?我只调用了一次。
你的"cash"setter调用了"cash"setter,调用了"cash"setter,调用了"cash" ] setter...
在 setter 中通过其自己的名称访问 属性 setter 会创建无限递归函数调用。
cash代表getter/setter,_cash代表'private'属性.
set cash(value) { // line 19
this._cash = value; // line 20
}
查看 this page 以获得清晰的示例。
您正在递归调用您的 getter。
它遵循一个可能的替代方案:
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 classes brings a new syntax for getters and setters on
object properties. Get and set allows us to run code on the reading or
writing of a property. ES5 had getters and setters as well but was not
widely used because of older IE browsers. ES5 getters and setters did
not have as nice of a syntax that ES6 brings us. So lets create a get
and set for our name property.
Source: 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'
我知道我迟到了,但我想我可以在这里澄清一两点:
首先是隐私问题,这是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 是 public 属性,因此您实际上不需要 getter和一个 setter 方法来处理它,因为你可以用 player1.cash 得到它并用 player1.cash = newCash;它正在抛出错误,因为 getter 和 setter 被递归调用,正如其他人提到的那样。
但是,如果您只是将 属性 重命名为 this._cash,您必须明白这 不是私有的 属性。如果您尝试访问 player1._cash,您将可以像访问 player1.cash 一样访问 属性 值].
那么,我们如何切实实施隐私保护?
使用 ES6/ES2015 有两种主要方法:使用新的原始类型 Symbol or using 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;
}
}
重要
虽然 Symbols 的语法更好,但它需要浏览器的本机支持才能实际工作。您可以使用转译器编写它,但在幕后,它会将其模拟为旧的 ES5 标准。对 WeakMaps 的原生支持更好,另一方面,此功能仅与 GC 和对象属性的可枚举选项一起使用。所以,最后,这是你的选择。
我目前正在试验 ECMA6 classes。 我当前的 class 如下所示
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 库有什么关系?为什么错误在同一行中出现多次?我只调用了一次。
你的"cash"setter调用了"cash"setter,调用了"cash"setter,调用了"cash" ] setter...
在 setter 中通过其自己的名称访问 属性 setter 会创建无限递归函数调用。
cash代表getter/setter,_cash代表'private'属性.
set cash(value) { // line 19
this._cash = value; // line 20
}
查看 this page 以获得清晰的示例。
您正在递归调用您的 getter。
它遵循一个可能的替代方案:
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 classes brings a new syntax for getters and setters on object properties. Get and set allows us to run code on the reading or writing of a property. ES5 had getters and setters as well but was not widely used because of older IE browsers. ES5 getters and setters did not have as nice of a syntax that ES6 brings us. So lets create a get and set for our name property.
Source: 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'
我知道我迟到了,但我想我可以在这里澄清一两点:
首先是隐私问题,这是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 是 public 属性,因此您实际上不需要 getter和一个 setter 方法来处理它,因为你可以用 player1.cash 得到它并用 player1.cash = newCash;它正在抛出错误,因为 getter 和 setter 被递归调用,正如其他人提到的那样。
但是,如果您只是将 属性 重命名为 this._cash,您必须明白这 不是私有的 属性。如果您尝试访问 player1._cash,您将可以像访问 player1.cash 一样访问 属性 值].
那么,我们如何切实实施隐私保护?
使用 ES6/ES2015 有两种主要方法:使用新的原始类型 Symbol or using 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;
}
}
重要
虽然 Symbols 的语法更好,但它需要浏览器的本机支持才能实际工作。您可以使用转译器编写它,但在幕后,它会将其模拟为旧的 ES5 标准。对 WeakMaps 的原生支持更好,另一方面,此功能仅与 GC 和对象属性的可枚举选项一起使用。所以,最后,这是你的选择。