便写高质量JavaSript的68个高效方法 >> 二章:变量作用域 >> 第12条:理解变量声明提升

JavaScript不支持块级作用域,即变量定义的作用域并不是离其最近的封闭语句或代码块,而是包含他们的函数。

bug1: 重声明

function isWinner(player,others){

  var highest = 0;

  for(var i = 0,n = others.length;i < n; i++){

    var player = others[i];

    if(player.score > highest){

      highest = player.score;
    }

  }

  return  player.score > highest;

}

   该程序在for循环体内声明了一个局部变量player。但是由于JavaScript中变量是函数级作用域(function-scoped),而不是块级作用域,所以在内部声明的player变量只是简单地重声明了一个已经存在于作用域内的变量(即参数player)。该循环的每次迭代都会重写同一变量。因此,return语句将player看作others的最后一个元素,而不是此函数最初的player参数。

理解JavaScript变量声明行为的一个好办法是把变量声明看作由两部分组成,即声明

JavaScript隐式地提升(hoists)声明部分到封闭函数的顶部,而将赋值;留在原地。换句话说,变量的作用域是整个函数,但仅在var语句出现的位置进行赋值。如图提供变量声明提升的可视化图。

     图    变量声明提升

bug2:   变量声明也可能导致变量重声明的混淆。在同一函数中多次声明相同变量是合法的。这在多个循环时会经常出现。

function trimSections(header,body,footer){

  for(var i = 0,n = header.length; i < n; i ++){

    header[i] = header[i].trim();

  }

  for(var i = 0,n = body.length; i < n; i ++){

    body[i] = body[i].trim();

  }

  for(var i = 0,n = footer.length; i < n; i ++){

    footer[i] = footer[i].trim();

  }

}
trimSections函数好像声明了6个局部变量(3个变量i,3个变量n),但经过变量声明提升后其实只声明了2个。
换句话说,经过变量声明提升后,trimSections函数等同于下面这个重写的版本。
for(var i = 0,n = body.length; i < n; i ++){
  body[i] = body[i].trim();
}
for(var i = 0,n = footer.length; i < n; i ++){
   footer[i] = footer[i].trim();
}
因为重声明会导致截然不同的变量展现,一些程序员喜欢通过有效地手动提升变量将所有的var声明放置在函数的顶部,从而避免歧义
无论你是否喜欢这种风格,重要的是,不管是写代码还是读代码,都要理解JavaScript的作用域规则。

例外:异常处理。try...catch语句将捕获的异常绑定到一个变量,该变量的作用域只是catch语句块。

 function test(){

    var x = "var", result = [];
    result.push(x);
    try{

      throw "exception";
    }catch(){
      x = "catch";
    }
    result.push(x);
    return result;
  }

  test();    //["var", "var"]

提示:

  • 在代码块中的变量声明会被隐式地提升到封闭函数的顶部。
  • 重声明变量被视为单个变量。
  • 考虑手动提升局部变量地声明,从而避免混淆。
原文地址:https://www.cnblogs.com/meiyanstar/p/13131649.html