简单介绍编译与变量、函数声明的关系。
- Javasript编译分两个阶段:
- 预编译阶段
- 将代码中的变量声明与声明式函数提前(预编译)
- 编译阶段
- 此时变量的赋值、函数执行等操作才会进行
- 预编译阶段
变量的声明
console.log(a); // undefined
var a = 1;
console.log(a); // 1
上面的代码我们可以这样看:
var a; // 变量a的声明被提升(预编译)
console.log(a); // undefined
a = 1; // 变量a被赋值为1
console.log(a); // 1
注意:从上面的代码我们可以看到变量的声明部分提升,赋值部分并不会被提升。
函数的声明
声明函数会被提前
foo(); // 2
function foo () {
console.log(2);
}
foo(); // 2
上面的代码我们可以这样看:
function foo () {
console.log(2);
}
foo(); // 2
foo(); // 2
函数表达式不会被提前
bar(); // TypeError: bar is not a function
var bar = function foo () {
console.log(3)
}
// foo(); // ReferenceError: foo is not defined
注意:我们尝试在函数表达式之后执行 foo(),结果抛出 ReferenceError: foo is not defined,当前作用域下找不到 foo,但是在 foo函数内部可以执行,也就是自己调用自己,注意会陷入死循环。
函数局部变量提升
局部变量在局部提升,外部访问不到。
foo();
function foo () {
console.log(a); // undefined
var a = 1;
console.log(a); // 1
}
声明同名函数
函数声明会被提前,同名函数后者会覆盖前者;
函数表达式不会被提前,同名变量声明 var foo; 提升会被忽略;
就是多个同名的变量声明,只会提升一次。
foo(); // 3
function foo () {
console.log(1);
}
var foo = function foo () {
console.log(2);
}
function foo () {
console.log(3);
}
foo(); // 2
if else for等创建代码块的语句,内部声明函数
foo();
if (true) {
function foo () {
console.log(1);
}
} else {
function foo() {
console.log(2);
}
}
代码块内部函数声明是否提前不同浏览器表现不一致, IE9及以下(更高版本没试过) => 输出 2,
函数处于 if else 代码块中,预编译阶段将其全部提前,即使 else 部分不会执行。
高级浏览器(Chrome、Firefox) => 抛出 TypeError: foo is not a function
只将函数名提升,函数体并未提升。
我们将函数执行的放到if 代码块中
if (true) {
foo();
function foo () {
console.log(1);
}
} else {
function foo() {
console.log(2);
}
}
IE9以下浏览器表示一致; 高级浏览器 => 输出 1 。
低版本浏览器中,预编译阶段即使处于 if else 、for 等创建代码块的语句,会将函数声明提前。
而高级浏览器中,只会提前函数名,只有当执行到相应代码块时,才会将全部提前。
函数内部的变量、函数声明与参数
foo(1);
function foo (a) {
console.log(a); // function a () {// ...}
var a= 2;
function a() {
// ...
}
console.log(a); // 2
}
简述执行顺序:
1.预编译阶段,foo函数声明被提前;
3.执行并传参foo(1),形参 var a = 1;
4.函数内部预编译,a函数声明被提前,var a 变量提前被忽略。
5.输出a => function a () {// …}
6.赋值a = 2;
7.输出a => 2
个人学习总结,如有不足欢迎指正。
参考博客:JavaScript提升(你不知道的JavaScript)