作用域
js的作用域有两种,全局作用域和局部作用域,对于 var 声明的变量,只有 function才可以为他创建局部作用域,对于let 声明的变量,支持块级作用域 { } 生成
变量提升
什么是变量提升?
在编译过程,将所有变量声明和函数声明提升到作用域顶部
JavaScript的源代码在运行的时候,会经过两个阶段:编译和执行。而且,编译阶段往往就在执行阶段的前几微秒甚至更短的时间内。
在编译的过程,会经历词法分析,语法分析,生成中间代码等过程,变量提升发生在编译阶段,生成可执行的中间代码。
提升原理
LHS查询
在编译的过程中,先将标识符和函数声明给提升到其对应的作用域的顶端。标识符解析的时候,会进行LHS查询,在LHS查询的时候,如果标识符一直找不到声明的位置,那么最终就会在全局环境生成一个全局变量。 LHS : 指的是赋值操作的左端。
提升案例
补齐声明
在解析过程中,如果找不到声明,最终在全局环境生成一个全局变量
function test(){
message = 'hi'
}
test()
console.log(message)
还原编译后代码
var message
function test(){
message = 'hi'
}
test() //message = 'hi'
console.log(message)
执行
hi
函数只提升声明式
函数提升,只会提升声明式函数,而不会提升函数表达式
f();
fn();//fn is not a function
//函数表达式
var fn = function(){
console.log(1)
}
//函数声明
function f(){
console.log(0)
}
编译结果
//函数声明
function f(){
console.log(0)
}
var fn = undefined;
f();
fn();
fn = function(){
console.log(1)
}
所以执行会报错
0
Uncaught TypeError: fn is not a function
at <anonymous>:2:1
再看下这个例子
function test() {
function f3(a) {
f = a;
console.log("1");
};
}
console.log(typeof f3); // undefined
重复声明优先 function
同名声明function会覆盖var声明的
add();
console.log(typeof add);
function add(){
console.log('加++');
}
var add;
编译
var add;
function add(){
console.log('加++');
}
add();
console.log(typeof add);