变量的作用域
在所有函数之外声明的变量,叫做全局变量,因为它可被当前文档中的任何其他代码所访问。在函数内部声明的变量,叫做局部变量,因为它只能在该函数内部访问。
ECMAScript 6 之前的JavaScript没有 语句块 作用域;相反,语句块中声明的变量将成为语句块所在代码段的局部变量。例如,如下的代码将在控制台输出 5,因为 x
的作用域是声明了 x
的那个函数(或全局范围),而不是 if
语句块。
if (true) {
var x = 5;
}
console.log(x); // 5
如果使用 ECMAScript 6 中的 let
声明,上述行为将发生变化。
if (true) {
let y = 5;
}
console.log(y); // ReferenceError: y is not defined
变量声明提升(Variable hoisting)
JavaScript 变量的另一特别之处是,你可以引用稍后声明的变量而不会引发异常。这一概念称为变量声明提升(hoisting);JavaScript 变量感觉上是被“提升”或移到了所有函数和语句之前。然而提升后的变量将返回 undefined 值。所以在使用或引用某个变量之后进行声明和初始化操作,这个被提升的引用仍将得到 undefined 值。
/**
* Example 1
*/
console.log(x === undefined); // logs "true"
var x = 3;
/**
* Example 2
*/
// will return a value of undefined
var myvar = "my value";
(function() {
console.log(myvar); // undefined
var myvar = "local value";
})();
上面的例子,也可写作:
/**
* Example 1
*/
var x;
console.log(x === undefined); // logs "true"
x = 3;
/**
* Example 2
*/
var myvar = "my value";
(function() {
var myvar;
console.log(myvar); // undefined
myvar = "local value";
})();
由于存在变量声明提升,一个函数中所有的var
语句应尽可能地放在接近函数顶部的地方。这将大大提升程序代码的清晰度。
在 ECMAScript 2015 中,let(const)将不会提升变量到代码块的顶部。因此,在变量声明之前引用这个变量,将抛出错误ReferenceError
。这个变量将从代码块一开始的时候就处在一个“暂时性死区”,直到这个变量被声明为止。
console.log(x); // ReferenceError
let x = 3;
函数提升(Function hoisting)
对于函数,只有函数声明会被提升到顶部,而不包括函数表达式。
/* 函数声明 */ foo(); // "bar" function foo() { console.log("bar"); } /* 函数表达式
表达式定义的函数,称为匿名函数。匿名函数没有函数提升。*/ baz(); // TypeError: baz is not a function //此时的"baz"相当于一个声明的变量,类型为undefined。 //由于baz只是相当于一个变量,因此浏览器认为"baz()"不是一个函数。 var baz = function() { console.log("bar2"); };