InternalError: 递归过多
当函数调用过多或函数缺少基本情况时,会发生 JavaScript 异常“递归过多”或“超出最大调用栈大小”。
消息
RangeError: Maximum call stack size exceeded (Chrome) InternalError: too much recursion (Firefox) RangeError: Maximum call stack size exceeded. (Safari)
错误类型
Firefox 中的 InternalError
;Chrome 和 Safari 中的 RangeError
。
哪里出错了?
调用自身的函数称为递归函数。满足条件后,函数停止调用自身。这称为基本情况。
在某些方面,递归类似于循环。两者都多次执行相同的代码,并且两者都需要一个条件(以避免无限循环,或者在这种情况下避免无限递归)。当函数调用过多或函数缺少基本情况时,JavaScript 会抛出此错误。
示例
此递归函数根据退出条件运行 10 次。
js
function loop(x) {
if (x >= 10)
// "x >= 10" is the exit condition
return;
// do stuff
loop(x + 1); // the recursive call
}
loop(0);
将此条件设置为极高的值将不起作用。
js
function loop(x) {
if (x >= 1000000000000) return;
// do stuff
loop(x + 1);
}
loop(0);
// InternalError: too much recursion
此递归函数缺少基本情况。由于没有退出条件,因此函数将无限地调用自身。
js
function loop(x) {
// The base case is missing
loop(x + 1); // Recursive call
}
loop(0);
// InternalError: too much recursion
类错误:递归过多。
js
class Person {
constructor() {}
set name(name) {
this.name = name; // Recursive call
}
}
const tony = new Person();
tony.name = "Tonisha"; // InternalError: too much recursion
将值分配给属性名称 (this.name = name;) 时,JavaScript 需要设置该属性。发生这种情况时,会触发 setter 函数。
在此示例中,当触发 setter 时,它被告知要再次执行相同的操作:设置它旨在处理的相同属性。这会导致函数一次又一次地调用自身,使其无限递归。
如果在 getter 中使用相同的变量,也会出现此问题。
js
class Person {
get name() {
return this.name; // Recursive call
}
}
为避免此问题,请确保在 setter 函数内部分配给的属性与最初触发 setter 的属性不同。getter 也是如此。
js
class Person {
constructor() {}
set name(name) {
this._name = name;
}
get name() {
return this._name;
}
}
const tony = new Person();
tony.name = "Tonisha";
console.log(tony);