功能范围

定义函数时,它会创建一个范围

函数外部的代码无法访问函数中定义的所有内容。只有此范围内的代码才能看到范围内定义的实体。

function foo() {
  var a = 'hello';
  console.log(a);  // => 'hello'
}

console.log(a);  // reference error

嵌套函数在 JavaScript 中是可能的,并且适用相同的规则。

function foo() {
  var a = 'hello';
  
  function bar() {
    var b = 'world';
    console.log(a);  // => 'hello'
    console.log(b);  // => 'world'
  }

  console.log(a);  // => 'hello'
  console.log(b);  // reference error
}

console.log(a);  // reference error
console.log(b);  // reference error

当 JavaScript 尝试解析引用或变量时,它会在当前范围内开始查找它。如果它在当前范围内找不到该声明,则会爬上一个范围来查找它。重复此过程直到找到声明。如果 JavaScript 解析器到达全局范围但仍无法找到引用,则将引发引用错误。

var a = 'hello';

function foo() {
  var b = 'world';

  function bar() {
    var c = '!!';

    console.log(a);  // => 'hello'
    console.log(b);  // => 'world'
    console.log(c);  // => '!!'
    console.log(d);  // reference error
  }
}

这种攀爬行为也可能意味着一个参考可能会覆盖外部范围中类似命名的参考,因为它首先被看到。

var a = 'hello';

function foo() {
  var a = 'world';

  function bar() {
    console.log(a);  // => 'world'
  }
}

Version >= 6

JavaScript 解析范围的方式也适用于 const 关键字。使用 const 关键字声明变量意味着不允许重新分配值,但在函数中声明它将创建一个新范围并使用新变量。

function foo() {
  const a = true;

  function bar() {
    const a = false;  // different variable
    console.log(a);   // false
  }

  const a = false;    // SyntaxError
  a = false;          // TypeError
  console.log(a);     // true
}

但是,函数不是创建范围的唯一块(如果使用 letconst)。letconst 声明具有最近的块语句的范围。有关详细说明,请参见此处