-
包括变量和函数在内的所有声明都会在任何代码被执行前先被处理。
-
原因:引擎会在解释JavaScript代码之前首先对其进行编译,编译阶段包括找到所有声明并用合适的作用域将它们关联起来,这也是词法作用域的核心内容。
-
注:只有声明本身会被提升,而赋值或其他运行逻辑会留在执行阶段
一、var变量声明提升
- 示例代码如下:
a=2;
var a;//提升
console.log(a);//2
console.log(b);//undefined
var b=2;//只提升了var b;
var b = 2;是被JavaScript看作是两个声明:var b;和 b=2;
- 第一个是定义声明 var b;是在编译阶段进行的
- 第二个是赋值声明 b = 2;是在执行阶段进行的
二、函数声明提升
函数声明会被提升,函数表达式不会被提升
foo1();//函数声明被提升,可以正常调用
function foo1() {
console.log(a);//undefined
var a=2;
console.log('foo1调用成功');
}
//每个作用域都有提升操作
foo2();//TypeError
bar();//ReferenceError
var foo2=function bar() {
console.log('调用成功');
}
- 这里的foo2()被提升并分配给所在作用域,因此不会导致ReferenceError
- 但foo此时并没有赋值,所以 foo() 是对undefined值进行函数调用,因此抛出TypeError异常
- 即便是具名的函数表达式,名称标识符在赋值之前也无法在所在作用域中使用
上述的foo2代码块经过提升后,实际上会被理解为以下形式
var foo2
foo2();//TypeError
bar();//ReferenceError
foo2=function bar() {
var bar=...
console.log('调用成功');
}
三、函数优先
函数声明会首先被提升,然后才是变量声明提升。
foo();//1
//函数声明会被提升到普通变量之前
//所以var foo被当作foo的重复声明忽略掉了
var foo;
function foo() {
console.log(1);
}
foo=function () {
console.log(2);
}
//输出的是1,该代码片段被引擎理解如下
function foo() {
console.log(1);
}
foo();//1
foo=function () {
console.log(2);
}
出现在后面的函数声明可以覆盖前面的
foo();//3
var foo;
function foo() {
console.log(1);
}
foo=function () {
console.log(2);
}
function foo() {
console.log(3);
}
四、小结
- 要var普通声明和函数声明混合用时要注意,
- 要避免重复声明。
网友评论