函数提升和变量声明前置

## 引言
在JavaScript中,我们可以在前面正常调用后面声明的函数而不会报错,当我们去使用一个变量时,无论这时变量声明在何方,都不会告诉我们xx is not define,最多给出一个undefined,这些情形之所以会发生,只是因为在JavaScript中存在着变量提升和声明前置这样的东西。

变量声明前置

正常情况下,我们这样去做变量的声明和使用:

1
2
var a = "hello world.";
console.log(a);

在这里当然能够正常的输出ahello world.,这一点是毋庸置疑的。
而当我们要直接去使用一个未经声明的函数时,则会报错:
console.log(c)
在这里c在上下文中都未出现,也就是说,浏览器也深知这一点,所以会用一串红色的警告来告诉我们c is not define
那么,如果我们先使用变量之后再去进行声明又会出现怎样的结果呢:

1
2
console.log(d);
var d = "hello JavaScript.";

我们会发现,这里的结果并不是一串红色的报错,也不是我们在后面写过的hello JavaScript.,而是输出一个undefined,这与我们前面的试验结果相悖,这里就必须提到JavaScript中关于变量提升了。
什么是变量提升呢,顾名思义,也就是说,变量被提到前面去了,那么它又是怎么提升的呢,根据前面一个例子可以得出,他绝不是全部提升,否则前面的例子就会输出hello JavaScript.而不是undefined了,根据变量提升,前面的代码会被解析成这样:

1
2
3
var d;
console.log(d);
d = "hello JavaScript.";

以此顺序解析,在第一行,声明了d,但是没有赋值,所以它的值就被默认为undefined,所以第二行输出结果为undefined,在第三行才是多其进行赋值。
根据以上,但我们在去看一行代码的输出时,应该先对其中先后顺序进行拆解,才能分析得出其中的值:

1
2
3
4
5
console.log(a);
var a = 1;
console.log(a);
console.log(b);
b = 10;

根据以上原则对函数顺序进行重新排列,得到这样的结果:

1
2
3
4
5
6
var a;
console.log(a); // undefined
a = 1;
console.log(a); // 1
console.log(b); // 报错 b is not define.
b = 10;

如此,结果便一目了然了…

函数提升

对于函数而言,其实这又有一点不一样了,但是根据以上原则进行试验,就可以得出结论了:

1
2
3
4
console.log(func());
function func(){
return "hello world.";
}

如果你真的去试了,你就会发现它输出的值是hello world.,正常将函数执行完成了,这也让我们得以知道函数提升和变量声明前置之间是不一样的,也就是说上面的代码其实是这样的:

1
2
3
4
function func(){
return "hello world.";
}
console.log(func());

这和正常执行顺序没什么两样,它的解析方式也和前面提到的相同,就是将代码的顺序进行重排,一切就完全在眼前了:

1
2
3
4
5
6
7
8
foo();
bar();
function foo(){
console.log("hello");
}
var bar = funciton(){
console.log("world");
}

方法如前:

1
2
3
4
5
6
7
8
9
var bar;
function foo(){
console.log("hello");
}
foo();
bar();
bar = function(){
console.log("world");
}

以上代码其实会因为语法错误而报错,因为bar不再是函数声明,而是函数表达式,这也就导致了函数提升的规则不会应用到它身上,这时直接运行bar()就会报错。