一、概念
提升
预编译期间会将变量声明与函数声明提升至其对应作用域的最顶端。
变量提升
console.log(a)//undefined
var a = 10
等价于
var a;
console.log(a)
a=10
函数提升
分为两种情况
1.对于命名函数的提升为
a()//hi
function a (){}
等价于
var a = function(){console.log('hi')}
a()
2.对于函数表达式的提升为
a() // ReferenceError:a is not a funciton
var a = function (){console.log('bye')}
等价于
var a; //undefined
a()
a = function(){console.log('bye')}
二、原则
牢记1个原则:提升只提升声明,不提升赋值
三、知识点
清楚以下5点知识:
1.变量函数提升是在js脚本预编译时进行的
2.对于在全局作用域的变量/函数会提升到整个代码顶部,在函数作用域里的变量/函数会提升到该函数作用域的顶部
3.对于var、function、function 在变量提升时会默认赋值undefined,而let、const不会默认赋值,所以可以理解为let、const不存在变量提升;函数提升只会提升命名函数,不会提升函数表达式类型的函数(因为该变量会被赋值为undefined,所以使用时会报错),可以直接理解为不会提升函数表达式
当程序的控制流程在新的作用域(module, function或block作用域)进行实例化时,在此作用域中的用let/const声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定,也就是对声明语句进行求值运算,所以是不能被访问的,访问就会抛出错误。所以在这运行流程一进入作用域创建变量,到变量开始可被访问之间的一段时间,就称之为TDZ(暂时死区)。
console.log(b) //ReferenceError: Cannot access 'b' before initialization
let b = 3
f() // '命名函数'
console.log(test) //undefined
test() //TypeError: test is not a function
function f(){
console.log('命名函数')
}
var test = function(){
console.log('函数表达式')
}
4.对于在函数作用域中使用某变量会现在该域中找,没有才会去全局作用域中找,var在函数内是有局部作用域的
//var在函数中是有局部作用域的,函数执行后便会被销毁,不会影响到外部的a
f() //2 函数提升
console.log(a) //undefined 变量提升
var a = 10
function f(){
var a = 2
console.log(a)
}
5.函数提升>变量提升
在函数foo()中,function a 会优先提升到函数最顶端
var a = 1;
function foo() {
a = 10;
console.log(a); //10
return;
function a() {};
}
foo();
console.log(a); //1
所以这段代码其实可以看成:
var a =1
function foo(){
var a = function {} //这个a是一个局部变量不会影响到外部的a
var a =10
console.log(a)
return
}
foo()
console.log(a)