Skip to content

一、无限递归一定会溢出吗?

  • 在浏览器控制台中运行foo函数,是否会导致堆栈溢出
    js
        function foo() {
            setTimeout(foo, 0); // 是否存在堆栈溢出错误?
        } 
        function foo() {
            setTimeout(foo(), 0); // 是否存在堆栈溢出错误?
        } 
        function foo() {
            Promise.resolve().then(foo);// 是否存在堆栈溢出错误?
        }

题解:

  • 从题中,知道在setTimeout中调用了foo,自己函数内部调用自己,属于无限递归,那会不会导致堆栈溢出呢?
  • 首先要知道栈溢出的原因是什么,比如在一个函数里面无限的调用自身,就容易导致栈溢出,为什么呢?
  • 因为每一次的函数调用,都会在栈里面加上一个执行上下文,其实就是会占用栈的一部分内存空间,而这个上下文呢,是要到函数结束了过后才会被弹出栈, 而如果说在这个函数里面,调用自身的话,就会导致这个函数还没有运行结束的时候,又在调用自己,又是一个函数调用,又会加一个进栈,一直加,一直调, 而栈的总大小是固定的,就会把栈撑爆,这就叫栈溢出。
  • 那么这里会不会导致栈溢出呢?不会。是因为在foo函数内部调用自己是用异步来操作的,setTimeout(foo, 0);,当在执行栈中加上一个执行上下文 在执行foo期间,并没有再次调用foo,只是在执行期间做了一个计时器,告诉你计时器到达了之后,再去调用foo,这就涉及到了事件循环,所以这一次的 foo是正常执行完成的,然后从事件队列里面取出这个foo函数,进行下一次调用,而这次调用是一样的,开一个计时器去计时,弹出栈,计时完成,进行下一次 调用。所以说这种情况下,不会导致栈溢出的。
  • 如果改成setTimeout(foo(), 0);,这个时候就会导致栈溢出了,这个时候就不是计时到了执行foo,而是先执行foo,把foo的返回结果,作为计时器 到达之后的要执行的东西,所以会导致栈溢出。
  • 还可以改成Promise.resolve().then(foo);,也是不会导致栈溢出。

Released under the MIT License.