调整字号

JavaScript 中的“变量声明提升”

本文翻译自Nettuts+

什么是提升(hoisting)?

假设有如下的代码:

var myvar = 'my value';
alert(myvar); // my value

显而易见,弹出窗口会显示 “my value” 。我们再建立一个立即执行的函数,显示同样内容:

var myvar = 'my value';
(function() {
  alert(myvar); // my value
})();

结果也很明显,现在,我们在这个匿名函数内建立一个同名的局部变量:

var myvar = 'my value';
(function() {
  alert(myvar); // undefined
  var myvar = 'local value';
})();

现在,弹出窗口为什么显示 undefined?我们声明的局部变量在 alert 之后,为什么对结果产生了影响?

变量声明被提升了(hoisted)

不管变量声明放在何处,它都会被自动地提升到所在作用域的顶部。但是,只是提升变量声明,而变量的初始化不会被提升,变量被声明后暂时被设定为 undefined

现在,解释一下声明(declaration)和初始化(initialization)的区别。假设有这样的语句:var joe = 'plumber';

它其实包含了声明和初始化两个步骤,这是声明(declaration):

var joe; // the declaration

这是初始化(initialization):

joe = 'plumber'; // the initialization

搞清楚了以后,就更容易明白了,假设有如下代码:

(function() {
  var a = 'a';
  // 一些代码
  var b = 'b';
  // 又一些代码
  var c= 'c'; // antipattern
  // 还是一些代码
})();

需要注意的是像上面这样并不是好的编码习惯(应该尽量把所有 var 都集中在顶部)。在这个例子中,所有的变量声明——不管它们出现在何处——都会在“幕后”被自动地提升到顶部,像下面这样:

(function() {
  var a, b, c; // 变量已经声明
  a = 'a';
  // 一些代码
  b = 'b'; // 初始化
  // 又一些代码
  c= 'c'; // 初始化
  // 还是一些代码
})();

原来如此

我们现在回到一开始那个 undefined 的问题:

经过上面的解释,在这里弹出 undefined 看起来就不奇怪了,因为函数内那句 myvar 的声明会被自动提升到函数这个局部作用域的顶部,也就是跑到了 alert 前面。所以执行 alert 的时候,myvar 其实已经被定义了,但因为初始化并没有被提升,所以此时变量的值是 undefined

注:除了变量声明,函数声明也会被提升,比如:

(function() {
  alert(typeof foo); // "function"
  function foo() {
    return "bar";
  }
})();

因为 foo 被提升到了作用域顶部,所以弹出“function”。另外,对于已存在的函数,如果再声明一个同名的变量,不会使函数变成 undefined。如:

(function() {
  alert(typeof foo); // 仍然是"function"
  function foo() {
    return "bar";
  }
  var foo;
})();

如果有兴趣可以试试5分钟听力练习,老外为你讲解:

还没有评论,沙发空缺中……
flight