js 变量提升,函数提升,以及为什么要变量提升??
一、变量提升
变量声明提升:
如果变量声明在函数里面,则将变量声明提升到函数的开头;
如果变量声明是一个全局变量,则将变量声明提升到全局作用域的开头;
变量提升分为两步,第一步变量声明的提升,第二步变量的赋值;
案例1:全局变量提升
console.log(a); // 'undefined' var a = '程序员劝退师'; console.log(a); // 程序员劝退师
实际运行时代码1:
var a; // 全局变量声明提升 console.log(a); // 'undefined' a = '程序员劝退师'; console.log(a); // 程序员劝退师
案例2:函数内变量提升
var a = 'global'; function fun() { console.log(a); // 'undefined' var a = 'local'; console.log(a); // local }
fun();
实际运行时代码2:
var a; // 全局变量声明提升 a = 'global'; // 声明后赋值 function fun() { var a; // 函数内变量声明提升 console.log(a); // 'undefined' a = 'local'; // 函数内赋值 console.log(a); // local } fun();
二、函数提升
函数的提升是直接将整个函数整体提升到作用域的最开始位置,相当于直接复制到开始;
函数声明只会提升函数声明,不提升函数表达式;
函数提升后会生成一个函数表达式;
案例1:函数声明式
console.log(fun1); // [Function: fun1] fun1(); // fun1 function fun1() { console.log('fun1'); }
运行时代码1:
var fun1 = function () { // 函数声明提升变为函数声明式 console.log('fun1'); }; console.log(fun1); // [Function: fun1] fun1(); // fun1
案例2:函数表达式,保持原来不变
console.log(fun2); // undefined fun2(); // TypeError: fun2 is not a function var fun2 = function () { console.log('fun2'); };
运行时代码2:
console.log(fun2); // undefined fun2(); // TypeError: fun2 is not a function var fun2 = function () { console.log('fun2'); };
三、提升顺序
函数声明提升比变量提升优先级要高,且不会被变量声明覆盖,但会被变量赋值时覆盖;
a() > a
案例:
console.log(a); // f a() {console.log(10)} console.log(a()); // undefined var a = 3; function a() { console.log(10); //10 } console.log(a); //3 a = 6; console.log(a()); //a is not a function;
运行时代码:
var a = function(){ // 函数声明提升 console.log(10); }; var a; // 变量声明提升 console.log(a); // f a() {console.log(10)} console.log(a()); // undefined a = 3; // 变量赋值后进行函数覆盖 console.log(a); // 3 console.log(a()); // a() is not a function;
四、变量提升的意义
我们知道在js运行时需要分两步,一步是解析阶段,一步是执行阶段;
1、容错性更好:
js作为一个脚本语言,在代码解析阶段,对js进行预编译,就可以发现一些语法上的错误,及时抛出错误,容错性更好;
2、提高西能:
在解析阶段函数的语法检查与预编译,操作只执行一次,目的为了提升性能,
如果没有这一步,代码在每次执行时都要进行编译运行,极大的浪费性能,相对于js这种脚本语言来说;
在解析的过程中,还会为函数生成预编译代码。在预编译时,会统计声明了哪些变量、创建了哪些函数,并对函数的代码进行压缩,去除注释、不必要的空
白等。这样做的好处就是每次执行函数时都可以直接为该函数分配栈空间(不需要再解析一遍去获取代码中声明了哪些变量,创建了哪些函数),并且因为
代码压缩的原因,代码执行也更快了。
es6之后带来了块级作用域极大地解决了变量提升带来的问题,我们在写代码时也应该尽量避免使用重复的变量。