变量提升就好比JavaScript引擎用一个很小的代码起重机将所有var声明和function函数声明都举起到所属作用域(所谓作用域,指的是可访问变量和函数的区域)的最高处。这句话的意思是:如果在函数体外定义函数或使用var声明变量。则变量和函数的作用域会提升到整个代码的最高处,此时任何地方访问这个变量和调用这个函数都不会报错;而在函数体内定义函数或使用var声明变量,变量和函数的作用域则会提升到整个函数的最高处,此时在函数体内任何地方访问这个变量和调用所定义的函数都不会报错。
示例如下:
- console.log("gv1=" + gv); // 在声明前访问变量
- show();
- var gv = "javascript";
- console.log("gv2=" + gv);
- function(){
- console.log("lv1= " + lv);
- vat lv = "js";
- console.log("lv2=" + lv);
- }
输出结果:
- gv1 = undefined;
- lv1 = undefined;
- lv2 = js;
- gv2 = javasript;
在上述代码中,第一行迪马以及show函数中的第一行代码分别是在变量声明前访问了gv和lv变量,第二行代码在函数定义前,调用了show函数。从输出结果来看,上述代码在声明之前访问变量以及在定义前调用函数完全没问题,原因是变量提升。
上述代码在代码运行前,经过预解析处理后的代码逻辑如下:
- var gv; // 变量声明提升到当前作用域的最高处
- var show = function show (){
- var lv;
- console.log("lv1=" + lv);//lv在声明时没有初始化,所以输出undefined
- lv= "js";
- console.log("lv2=" + lv); // 变量输出赋予的值: js
- }
- console.log("gv1=" + gv1); // gv在声明时没有初始化,所以输出undefined
- gv = "javascript";
- console.log("gv2=" + gv);//变量输出所赋予的值:javascript
由上可见,正是因为var支持变量提升,所以可以在声明前使用var声明的变量,而let和const不支持变量提升,所以它们声明的变量必须先声明才可以使用。
一般来说,javascript代码的执行包括两个过程:预解析处理过程和逐行解读过程。在代码逐行解读前,javascript引擎需要进行带的预解析处理。在预解析过程中,当前作用域中var变量声明和函数定义将被提升到作用域的最高处。