JS作用域的问题

今天看到一个前端有趣的前端面试问题,特此记录,分享一下自己的一些看法。

问题

解释下面代码的输出的结果及原因。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var a = 1;
function fn() {
console.log(a);
var a = 5;
console.log(a);
a++;
var a;
fn2();
console.log(a);
function fn2(){
console.log(a);
a = 20;
b = 100;
}
}
fn();
console.log(a);
a = 10;
console.log(a);
console.log(b);
这个题目主要在考察JavaScript中变量的作用域和变量声明提升。掌握了这两个知识点,这个题目就变得很容易解决。

变量的作用域

MDN有关于变量作用域的详细解释。

在函数之外声明的变量叫做全局变量,可被当前文档中的任何其他代码访问;在函数内部声明的变量叫做局部变量,只能在该函数内部访问。

除此之外还要注意在ECMAScript 6之前JavaScript并没有语句块作用域。

变量声明提升

变量声明提升 Variable hoisting 是JAVASCRIPT的一个比较特别的地方。简单的来说就是可以引用在当前代码之后声明的变量但不产生任何异常,被引用的变量将会返回 undefined,所以看上去是将该变量的声明进行了提前。更详细的内容可以参考MDN变量声明提升

分析

该问题的代码变为如下形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var a;  // 声明全局变量
a = 1; // 赋值
function fn() {
var a; // 局部变量声明提升
var a;
console.log(a); // undefined
a = 5;
console.log(a); // 5
a++; // 6
fn2();
console.log(a); // 20
function fn2(){
console.log(a); // 6
a = 20;
b = 100; // window.b = 100
}
}
fn();
console.log(a); // 全局
a = 10;
console.log(a); // 10
console.log(b); // 100