Javascript 面试题——递归、上下文、函数、栈、变量提升

面试题

1. 以下代码输出了什么?

2. 整个过程产生了几个上下文?

 1 console.log('global begin: ' + i); // ?
 2 var i = 1;
 3 foo(1);
 4 function foo(i) {
 5     if (i == 4) {
 6         return;
 7     }
 8     console.log('foo() begin: ' + i); // ?
 9     foo(i+1);
10     console.log('foo() end: ' + i); // ?
11 }
12 console.log('global end: ' + i); // ?

输出分析

第一行代码输出的是 undefined。为什么是 undefined,而不是报错?代码不是从上往下执行吗?这个就需要了解代码的预处理机制,其实上面的代码就等同于:

var i;
console.log('global begin: ' + i);
i = 1;

这种现象叫做变量提升。包括函数也是一样,但函数提升是直接创建的,所以要区分变量和函数提升。

foo(); // 报错,仅变量提升,值为 undefined
bar(); // 不报错,已经创建函数
var foo = function () {
    
};
function bar() {
    
}

 还有补充一点就是先变量提升再函数提升,示例:

1 function foo() {
2     
3 }
4 var foo;
5 console.log(typeof foo); // "function"

 

第 12 行输出的也是 1,这是作用域相关的知识点。

 

最麻烦的是 foo 函数,它是一个递归函数,里面到底怎么工作的,看下面的执行上下文栈

foo(i + 1 = 4)
foo(i + 1 = 3)
foo(i + 1 = 2)
foo(1)
window

 

当函数递归到 foo(4) 的时候,满足条件 i == 4 结束递归,退出了函数 foo(4),函数退出了就会从栈中移除,所以就变成了

foo(i + 1 = 3)
foo(i + 1 = 2)
foo(1)
window

foo(4) 退出后会执行 foo(3) 后面剩余的代码,此时的 i 当然等于 3。举个例子:

1 test(1);
2 function test(i) {
3     test2(i + 1);
4     console.log('test end: ' + i); // test2 退出后就执行我了
5 }
6 
7 function test2(i) {
8     return
9 }

以此类推,foo(3)剩余代码执行完后就退出函数,然后再执行 foo(2) 剩余的代码。。

 

foo(i + 1 = 2)
foo(1)
window

到最后就保留了 window 上下文,所以一共有5个上下文产生。

所以最后输出是:

undefined

1

2

3

3

2

1

1

总结

这主要是考查你对Javascript中执行上下文栈的理解。其实这就是个嵌套调用函数,如果要把它拆解成普通的嵌套就十分繁琐,比如下面的,结果一样,估计这样会好理解些。

 1 console.log('global begin: ' + i);
 2 var i = 1;
 3 foo(1);
 4 function foo(i) {
 5     console.log('foo() begin: '+ i);
 6     foo2(i+1);
 7     console.log('foo() end: '+ i);
 8 }
 9 function foo2(i) {
10     console.log('foo() begin: '+ i);
11     foo3(i+1)
12     console.log('foo() end: '+ i);
13 }
14 function foo3(i) {
15     console.log('foo() begin: '+ i);
16     foo4(i+1);
17     console.log('foo() end: '+ i);
18 }
19 function foo4(i) {
20     return;
21 }
22 console.log('global end: ' + i);

 

posted @ 2019-10-04 17:09  sku  阅读(706)  评论(0编辑  收藏  举报