什么是变量晋升?

定义:变量晋升是当栈内存作用域造成时JS代码执行前,浏览器会将带有var, function关键字的变量提前进行申明 declare(值默认就是 undefined),定义 defined(就是赋值操作),这种事后解决的机制就叫做变量晋升机制也叫预约义

1. 带Var申明与不带Var申明的变量晋升
区别:var操作符定义的变量会成为蕴含他的函数的局部变量。不过在函数外部定义变量时省略var操作符能够定义一个全局变量。

function foo() {     a = 0;     var b = 0;}  foo()  console.log(a);//0  console.log(b);//Uncaught ReferenceError: b is not definedvar a = b =12   // 这里的 b 也是不带 var 的。/* 相当于var a = 12;b = 12*/

var申明相干变量晋升练习题--1:

console.log(a, b)var a =12, b ='小白'function foo(){    console.log(a, b)    var a = b =13    console.log(a, b)}foo()console.log(a, b)/* 输入:    undefined undefined    undefined "小白"    13 13    12 13*/

解释--1:
1)a和b相当于定义了两个window变量,变量在代码执行前定义但未赋值,所以此时为undefined undefined;
2)当代码执行到函数时,第一个console.log(a, b)时,函数中的局部变量a的定义被晋升然而b未声明,因而作用域链以后流动对象(函数上下文)找不到b的申明,从而寻找下一个蕴含上下文流动对象,找到 b ='小白',所以此时打印undefined "小白";
3)当执行了var a = b =13,别离为函数局部变量a和全局变量b赋值后,此时打印的为13 13;
4)因为函数赋值的变量a为局部变量,b为全局变量,所以此时打印的a,b都是全局变量,因而a的值不变,b的值赋值为13,因而打印12 13;
var申明相干变量晋升练习题--2:

  console.log(a, b)  var a =12, b = '小白'  function foo(){    console.log(a, b)  }  foo()  console.log(a, b)  /* 输入:      undefined undefined      12 "小白"      12 "小白"  */

解释--2:
1)var变量申明晋升到顶端,但未赋值,因而打印为undefined undefined
2)拜访全局变量
3)拜访全局变量
var申明相干变量晋升练习题--3:

  a = 2  function foo() {    var a = 12;    b = '小白'    console.log('b' in window)    console.log(a, b)  }  foo()  console.log(b)  console.log(a)  /* 输入:  true  12 '小白'  小白  2  */

解释--3:
1)b未用var操作符申明,因而默认定义未window变量,因而打印true
2)函数执行过程中以后流动对象会被压入作用域链最顶端,从作用域链中以后流动对象中寻找变量,如果找不到,才回去寻找下一个蕴含上下文的流动对象,因而此时打印的a为12;
3)在函数内部打印变量a,b那么以后的上下文的流动对象便是window对象,因而打印的时全局变量a,b;
var申明相干变量晋升练习题--4:

  fn();  console.log(v1);  console.log(v2);  console.log(v3);  function fn() {    var v1 = v2 = v3 = 2019;    console.log(v1);    console.log(v2);    console.log(v3);  }  /*输入      2019      2019      2019      Uncaught ReferenceError: v1 is not defined  */

解释--4:
1)函数申明也会晋升,因而2019、2019、2019都是函数中打印的局部变量,当函数执行结束后,window流动对象中并未定义v1、v2、v3因而此时报错。
2. 等号右边下的变量晋升

= 意味着赋值,因而右边应该为变量,左边都应该是值,因而只对等号右边的进行变量晋升

等号右边下的变量晋升相干变量晋升练习题--1:

  print()  function print(){    console.log('小白')  }  print()  /* 输入:  小白  小白  */

解释--1:
1)因为function关键字也会变量晋升,因而不难理解相当于调用了两次print()办法,因而打印两次小白;
等号右边下的变量晋升相干变量晋升练习题--2:

  console.log(printf)//undefined  printf()//Error  var printf = function () {    console.log('林一一')  }  printf()//未执行  /*输入      undefined      Uncaught TypeError: print is not a function  */

解释--2:
1)同样因为变量晋升机制带 var 的 print 是一开始值是 undefined
2)因为1),并且此时并未给printf赋值成函数,所以 print() 这时还不是一个函数,所以报出 类型谬误TypeError
等号右边下的变量晋升相干变量晋升练习题--3:

  var fn = function sum() {    console.log(sum);//=>函数自身    console.log(1);//=>1  }  // sum();//=>Uncaught ReferenceError: sum is not defined  fn();  /* 输入:  ƒ sum() {    console.log(sum);//=>函数自身    console.log(1);//=>1  }    1   */

解释--3:
1)sum()是匿名函数具体化后的名字,只能够在函数上下文中应用,因而蕴含上下文中拜访报Error;
2)fn定义晋升并初始化为undefined后,执行到sum()为fn从新赋值,在调用sum能够失常输入。
2. 条件判断下的变量晋升
以后作用域不论条件是否成立都要进行变量晋升 ,function在老版本浏览器 (IE10以下)的渲染机制下,申明和定义都解决,然而为了投合es6中的块作用域, 新版本浏览器对于在条件判断中的function不论条件是否成立,都只是先申明,没有定义 相似于var ,同时判断体中如果呈现了let、const、function会创立一个新的执行上下文即块级上下文。

条件判断下的变量晋升相干变量晋升练习题(变量和函数晋升的区别)--1:

  console.log(a); // undefined  console.log(b); // undefined  if (true) {    console.log(a); // undefined    var a = 1;    console.log(b); // ƒ b() {console.log("1");}    function b() {      console.log("1");    }  }  console.log(a); // 1  console.log(b()); // 1,undefined  /* 输入:  undefined  undefined    ƒ b() {      console.log("1");    }      1  1  undefined//因为函数b()没有返回值,因而console.log(b()),b()执行时打印1,执行结束打印undefined  */

解释--1:
1) 在以后作用域下不论条件是否成立都要进行变量晋升,为了投合es6中的块作用域, 新版本浏览器对于在条件判断中的function不论条件是否成立,都只是先申明,没有值。因而,a、b打印的都是undifined。
2)在执行到if(){}语句块中,变量执行到赋值语句才赋值,而函数间接赋值
3)if执行完结,赋值操作完结,因而能够打印a,b();
条件判断下的变量晋升相干变量晋升练习题(变量晋升)--2:

  console.log(a)  if(true){    console.log(a)    var a = '小白'  }  console.log(a)/* 输入    undefined    undefined    小白/

解释--2:
1)无论条件是否成立,都会进行变量晋升,因而打印undefined;
2)赋值后从新打印a;
条件判断下的变量晋升相干变量晋升练习题--3:

  // console.log(f)//Uncaught ReferenceError: f is not defined  if(function f(){}){    console.log(typeof f)//undefined  }

解释--3:
1)if 中 () 内的表达式不会变量晋升;
2)判断的条件没有晋升,所以条件外部的 f 是未定义

认真比照如下代码:

  console.log(globalPrint)//ƒ globalPrint(){}  console.log(fatherPrint)//undefined  console.log(childPrint)//undefined  function globalPrint(){}  if(true) {    console.log(globalPrint)//ƒ globalPrint(){}    console.log(fatherPrint)//ƒ fatherPrint() {}    console.log(childPrint)//undefined    function fatherPrint() {}    if(false){      console.log(globalPrint)//      console.log(fatherPrint)//      console.log(childPrint)//      function childPrint(){        console.log(1)//        return "childPrint()的返回值";      }    }  }  console.log(childPrint)//undefined
  console.log(globalPrint)//ƒ globalPrint(){}  console.log(fatherPrint)//undefined  console.log(childPrint)//undefined  function globalPrint(){}  if(true) {    console.log(globalPrint)//ƒ globalPrint(){}    console.log(fatherPrint)//ƒ fatherPrint() {}    console.log(childPrint)//undefined    function fatherPrint() {}    if(true){      console.log(globalPrint)//ƒ globalPrint(){}      console.log(fatherPrint)//ƒ fatherPrint() {}      console.log(childPrint)//ƒ childPrint(){console.log(1)return "childPrint()的返回值";}      function childPrint(){        console.log(1)//1        return "childPrint()的返回值";      }    }  }  console.log(childPrint())//childPrint()的返回值

总结:

  • if()判断语句中申明的办法无论在全局上下文或函数的执行上下文中,函数都无奈晋升。
  • if{}语句块中,var变量和函数都会作用域晋升,然而函数赋值是在进入语句块之后,而变量赋值是在执行赋值语句后。
  • 函数变量会晋升,然而只有代码执行到函数申明的语句块时才会立刻赋值,因而父级上下文拜访子上下文中的函数时为undefined(缺省值:申明了但未赋值)。

(未完...)
参考资料:

  • 彻底解决 JS 变量晋升| 一题一图,超具体包教包会
  • JS中的变量晋升
了解尚浅,望不吝赐教!