Javascript中递归造成的堆栈溢出及解决⽅案
关于堆栈的溢出问题,在Javascript⽇常开发中很常见,Google了下,相关问题还是⽐较多的。本⽂旨在描述如何解决此类问题。⾸先看⼀个实例(当然你可以使⽤更容易的⽅式实现,这⾥我们仅探讨递归):
function isEven (num) {
if (num === 0) {
return true;
}
if (num === 1) {
return fal;
}
return isEven(Math.abs(num) - 2);
结果运用
}
//Outputs: true
console.log(isEven(10));
//Outputs: fal
console.log(isEven(9));
当我们把参数改成10000时,运⾏下例会发⽣堆栈溢出:
function isEven (num) {
if (num === 0) {
自制米粉
return true;
}
if (num === 1) {
return fal;
}
return isEven(Math.abs(num) - 2);
}
//不同的javascript引擎报错可能不同
//Outputs: Uncaught RangeError: Maximum call stack size exceeded
console.log(isEven(10000));
原因是每次执⾏代码时,都会分配⼀定尺⼨的栈空间(Windows系统中为1M),每次⽅法调⽤时都会在栈⾥储存⼀定信息(如参数、局部变量、返回值等等),这些信息再少也会占⽤⼀定空间,成千上万个此类空间累积起来,⾃然就超过线程的栈空间了。那么如何解决此类问题?
使⽤闭包:
function isEven (num) {
货币战争读后感if (num === 0) {
return true;
}
if (num === 1) {
return fal;
}
return function() {
return isEven(Math.abs(num) - 2);
}
}
//Outputs: true
console.log(isEven(4)()());
此时每次调⽤时,返回⼀个匿名函数,匿名函数执⾏相关的参数和局部变量将会释放,不会额外增加堆栈⼤⼩。
优化调⽤:
上例调⽤⽐较⿇烦,优化如下:
function isEven (num) {
if (num === 0) {煤矿工作总结
return true;
}
if (num === 1) {
return fal;
}
return function() {
return isEven(Math.abs(num) - 2);
}
}
function trampoline (func, arg) {
var value = func(arg);
while(typeof value === "function") {
value = value();
}
return value;
积化和差公式
}
/
/Outputs: true
console.log(trampoline(isEven, 10000));
//Outputs: fal
console.log(trampoline(isEven, 10001));
现在我们可以解决堆栈溢出问题了,但是不是感觉每次tarmpoline(isEven, 1000)这种调⽤⽅式不是很好,我们可以使⽤来绑定:function isEven(n) {
/**
* [isEvenInner 递归]
* @param {[type]} num [description]
* @return {Boolean} [description]
*/
function isEvenInner (n) {
卢沟桥的狮子歇后语
if (n === 0) {
return true;
老师祝福语简短}
if (n === 1) {
return fal;
}
return function() {
return isEvenInner(Math.abs(n) - 2);
}
}
/**
* [trampoline 迭代]
* @param {[type]} func [description]
* @param {[type]} arg [description]
* @return {[type]} [description]
*/
function trampoline (func, arg) {
var value = func(arg);
while(typeof value === "function") {
value = value();
}
return value;
}
return trampoline.bind(null, isEvenInner)(n);
}
//Outputs: true
console.log(isEven(10000));
//Outputs: fal
console.log(isEven(10001));
虽然上例实现了我们想要的效果,但是trampoline函数还是有⼀定的局限性:
1.假设你只传递⼀个参数给递归函数
value = func(arg); 修改为 value = func.apply(func, arg);
2.假设最后的返回值不是⼀个函数关于更健壮性的实现,请看中源码。
感谢您的阅读,⽂中不妥之处还望批评指正,⽂章已同步⾄如果你有好的建议,欢迎留⾔,么么哒!
转载声明:
本⽂标题:
一直打哈欠