前端Web前端之路

变量声明中的变量提升(var hoisting)

2017-05-10  本文已影响302人  唯泥Bernie

今天讲讲变量声明和变量提升(var hoisting)。有一类题目会问你在变量声明前去获取这个变量值,会获取到什么值或者产生什么情况。我以下面的示例代码来说明下,当我们运行一个函数时发生了什么?(为了言简意赅,我简化了规范中的步骤,只做一个大概的说明,详情请参考 ES6 规范

var foo1 = 'foo1';
var foo2 = 'foo2Outer';

function exampleFunc() {
  console.log( foo1 ); // foo1
  console.log( foo2 ); // undefined
  console.log( bar ); // undefined
  console.log( varFunc ); // undefined
  console.log( expFunc ); // function expFunc() {alert( 'second' )}
  console.log( localVarUndefined );
  // Firefox -> ReferenceError: can't access lexical declaration `localVarUndefined' before initialization
  // Chrome -> Uncaught ReferenceError: localVarUndefined is not defined
  console.log( localVar ); 
  // Firefox -> ReferenceError: can't access lexical declaration `localVar' before initialization
  // Chrome -> Uncaught ReferenceError: localVar is not defined

  var foo2 = 'foo2Inner'
  var bar = 'bar';
  var varFunc = function() {
  }
  function expFunc() {
    alert( 'first' );
  }
  function expFunc() {
    alert( 'second' );
  };
  var expFunc;
  /* ----- let declared variable ---- */
  let localVarUndefined;
  let localVar = 'localVar';

  console.log( localVarUndefined ); // undefined
  console.log( localVar ); // localVar
}

exampleFunc();

exampleFunc 函数被调用后发生的步骤:

  1. 生成执行上下文和作用域并做一定的初始化。(如果对执行上下文是什么不了解的话,详见《什么是作用域和执行上下文》。初始化过程还涉及 this 的初始化,详见《function作为构造函数和非构造函数调用的区别》
  2. 对形式参数进行初始化(这篇我们就先不具体解释这步)。
  3. 遍历函数体,寻找声明的变量,并按一定的规则生成这些变量放在作用域中(注意这里仅仅是生成变量,忽略等号后面赋值语句,即使声明和赋值写在一起)。
  4. 按程序逻辑从上到下运行函数体。

接下来我们逐一分析示例代码中的各种情况:

所以 expFunc 在函数体运行前,变量创建过程中变成了 function expFunc() {alert( 'second' )}。当然如果函数体运行后再对 expFunc 进行赋值后,其又可以变成其他:

function exampleFunc() {
  console.log( expFunc ); // function expFunc() {alert( 'second' )}
  
  function expFunc() {
    alert( 'first' );
  }
  function expFunc() {
    alert( 'second' );
  };
  console.log( expFunc ); // function expFunc() {alert( 'second' )}
  var expFunc = 'str';
  console.log( expFunc ); // str
}

exampleFunc();

<br />
到这里为止,我们看到了变量声明在 ES6 之前的大致行为,这就是所谓的变量提升(var hoisting):函数运行的过程像是把函数体内所有变量的声明(创建)都提到了函数的最前面。

上一篇下一篇

猜你喜欢

热点阅读