# 变量提升和函数提升
# 变量提升
js在执行过程中进入新的函数时,函数内部被声明的所有变量都会被移动到函数最开始的地方。被提升的只有变量的声明,赋值还在原来的位置。变量会优先查找当前函数内部被声明的局部变量,找不到才会找全局变量。
变量提升只有声明被提示,而不提示初始化
变量提升是将变量声明提升到它所在当前作用域{}
的最开始的部分。
console.log(a)
var a = 1;
// 变量提升后等价于下面代码
var a;
console.log(a) // undefined
a = 1
首先在当前作用域内寻找,当前作用域没有变量声明再去外部寻找。
var a = 1;
function fn() {
console.log(a)
var a = 2;
console.log(a)
}
// 变量提升后等价于下面代码
var a = 1;
function fn() {
var a; // 就是外部有同名的变量,也要先查找当前作用域下的声明的变量
console.log(a) // undefined
a = 2;
console.log(a) // 2
}
# 函数提升
js中创建函数有两种方式:函数声明式和函数字面量式。只有函数声明才存在函数提升 表达式通过变量保存函数和变量提升一样。
console.log(f1);
console.log(f2);
function f1() {}
var f2 = function() {}
// 函数提升后等价于下面代码
function f1() {}
var f2;
console.log(f1); // function f1() {}
console.log(f2); // undefined 这种声明就相当于变量提升一样了
f2 = function() {}
# 变量提升与函数提升
函数提升优先于变量提升
看一道面试题,执行fn输出什么
var a = 1;
function fn(a) {
console.log(a)
var a = 2;
function a() {}
console.log(a)
}
// 分析
var a = 1;
function fn(a) {
console.log(a) // function a() {}
function a() {} // 变量提升到最前面
var a; // 行参相当于var a,所以也在函数后面
a = 3;
var a; // 函数内部声明的a,覆盖了形参
a = 2;
console.log(a) // 2
}
// 所以输入如下
fn(3)
// ƒ a() {}
// 2
另一道面试题:
var a=2;
function a() {
console.log(3);
}
console.log(typeof a);
// 变量提升和函数提升后,代码变为
function a() {
console.log(3);
}
a=2;
console.log(typeof a); // number
变量和函数提升后,再按顺序执行,在上面先获取上面的,在下面就获取最下面的
console.log(a);
var a=2;
function a() {}
// 相当于
console.log(a); // function a() { }
function a() {}
var a=2;
var a=2;
function a() {}
console.log(a);
// 相当于
function a() {}
var a=2;
console.log(a); // 2
# var function 和 let const
js中无论哪种形式声明(var,let,const,function,function*,class
)都会存在提升现象,不同的是, var,function,function*
的声明会在提升时进行初始化赋值为 undefined
,因此访问这些变量的时候,不会报ReferenceError
异常,而使用 let,const,class
声明的变量,被提升后不会被初始化,这些变量所处的状态被称为“temporal dead zone
”,此时如果访问这些变量会抛出ReferenceError
异常,看上去就像没被提升一样。
# 为什么有变量提升
js和其他语言一样,都要经历编译和执行阶段。而js在编译阶段的时候,会搜集所有的变量声明并且提前声明变量,而不会改变其他语句的顺序,因此,在编译阶段的时候,第一步就已经执行了,而第二步则是在执行阶段执行到该语句的时候才执行。
补充:
变量提升的本质其实是由于js引擎在编译的时候,就将所有的变量声明了,因此在执行的时候,所有的变量都已经完成声明。
当有多个同名变量声明的时候,函数声明会覆盖其他的声明。如果有多个函数声明,则是由最后的一个函数声明覆盖之前所有的声明。
遇到面试考察变量提升问题,首先就要先提升变量,再考虑其他的。
← 正则表达式 赋值与浅拷贝、深拷贝 →