提升
1.为什么会存在“提升”
-
编译器的工作:
根据第一章中的介绍,我们可以知道,引擎会在JS代码执行之前首先对其进行编译。编译阶段其中一部分工作就是找到所有的声明,并用合适的作用域将它们关联起来。 -
编译完后才执行:
包括变量和函数在内的所有声明都会在任何代码执行之前首先被处理(代码虽是顺序执行,但它是在编译完成之后才开始的) -
仅声明提前:
声明和赋值是两件事,即使它们被写在同一行代码里,eg:var a = 2;
上述代码会被看成两句话:
var a
和
a = 2
,其中
var a
变量a的声明会在编译阶段完成,而
a = 2
赋值语句将会被留在原地,等待程序顺序执行。
2.函数提升
-
函数声明和变量声明一样,也存在着“提升”
foo() function foo () { //... }
-
需要注意的是,仅函数声明会被提升,而
函数表达式不会
,eg:foo() // TypeError,而非ReferenceError var foo = function bar() { //... }
上述代码,
var foo
会被声明提前,但此时它仅仅是一个变量(初始值为undefined),而非方法,不能用“()”进行调用,所以会报
TypeError
类型错误 -
即使是具名的函数表达式,名称标识符在赋值之前也无法在所在作用域中使用:
foo() // TypeError bar() // ReferenceError var foo = function bar () { //... }
上述代码中,
var foo
会被声明提前,但尚未赋值时其初始值为undefined,对undefined值进行函数调用会导致非法操作,报TypeError(同上一点);
而
bar
没有被声明提前
,在程序执行到上述第三行之前,它都是尚未在程序中存在,所以引擎对
bar
进行的RHS查找会报ReferenceError
3.变量提升和函数提升谁优先
-
结论:
函数声明会首先被提升,eg:
foo() // 打印 1
var foo; // 变量声明提升
function foo () { // 函数声明提升
console.log(1)
}
foo = function () { // 函数表达式不提升
console.log(2)
}
-
原因:
这里涉及到一个重复声明的处理:
使用var重复声明一个变量在JS中合法且不会报错(前提)
若重复声明的变量有初始值,那么它的作用等同于赋值
若重重复声明的变量没有初始值,那么它对之前的变量不存在任何影响
以下是我自己对于重复的变量和函数声明提升优先顺序的想法,可能想的有点复杂,但帮助理解应该还是可以的
若是变量声明和函数声明的提升优先顺序如下:
1.如果,变量提升优先:
var foo;
function foo() { //... }
函数声明foo可以被看作是有初始值的重复声明,根据上述第二点,它会被当做赋值处理,所以,在对foo进行函数调用时没有报错,且此时foo不再是一个变量,而是一个函数的标识符了
2.如果,函数提升优先:
function foo() { //... }
var foo;
第二行的声明根据上述第三点来讲,它是一个没有初始值的重复声明,所以会被忽略掉。foo还是一个函数的标识符,会进行函数调用
总而言之记住这一句就好:
函数声明会优先于变量提升,且重复的var变量声明会被忽略
-
注意:
虽然函数声明提升优先于变量,但出现在后面的函数声明是会覆盖前面的声明的!!