一道试题引发对函数执行栈的思考

99 阅读2分钟

首先题目是这样的:

console.log('bg' + n);
var n = 1;
foo(1);
function foo(n) {  
  if (n === 3) {    
    return   
 }    
console.log('start' + n); 
   foo(n + 1) 
   n = n + 1;  
   console.log('end' + n)
}
 console.log('ge' + n)

第一行因为var声明的变量,会有声明提升,但是赋值操作不会被提升,所以毫无疑问会输出 'bgundefined'。

然后执行foo(1),进入函数体。

函数看起来很简洁,用了递归,但是仔细分析一下,觉得有些吃力。start后面的n是根据递归走的每次+1输出,n=3时结束递归,不再执行start的输出。也就是依次输出   'bgundefined','start1','start2'。

然而end后面的n又是怎样变化的呢?

可以这样分析,这个函数里面并不存在异步任务,代码自上而下一步步执行,遇到函数执行肯定是要将函数执行完才会继续下面的执行。 foo(1)执行会生成foo(2),然后继续生成foo(3)。foo(1)、foo(2)、foo(3)全都会被压入函数执行栈中,这三个函数只有foo(3)是在end输出之前就return的,foo(1)和foo(2)仍然存在栈中,根据执行栈的后进先出的特点,递归结束以后,foo(2)在栈顶,会继续先执行foo(2),此时n=2,输入'end3',执行完从栈中弹出。再执行foo(1),此时n=1,输出'end2'。

然后最后一行,除非在函数中直接引用变量名才会令变量发生改变。因为n是当做形参传入的函数,在全局作用域中不会发生改变,仍然输出 'ge1'。

这道题已经困扰了我好几天,今天终于有种豁然开朗的感觉。学而不思则罔,思而不学则殆,多思考,学习知识才能事半功倍!