JavaScript不支持块级作用域,变量定义的作用域并不是离其最近的封闭语句或代码块,而是包含它们的函数。
// 每次循环都会重写player变量,最后return的player不再是当初传入的player参数
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;
}
复制代码
将变量声明看作两部分,声明与赋值来理解JavaScript变量声明行为。JavaScript隐式地提升声明部分到封闭函数的顶部,而将赋值留在原地。
function f() {
// ...
// ...
{
// ...
var x = /*...*/;
// ...
}
}
// 等效于
function f() {
var x;
// ...
{
// ...
x = /*...*/;
// ...
}
}
复制代码
变量声明提升也可能导致变量重声明的混淆。
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();
}
}
// 变量提升,通过变量提升后6个局部变量(3个变量i,3个变量n)其实只声明了2个。
function trimSections(header, body, footer) {
var i, n;
for (i = 0, n = header.length; i < n; i++){
header[i] = header[i].trim();
}
for (i = 0, n = body.length; i < n; i++){
body[i] = body[i].trim();
}
for (i = 0, n = footer.length; i < n; i++){
footer[i] = footer[i].trim();
}
}
复制代码
在JavaScript的异常处理中存在块级作用域。
// try...catch语句将捕获的异常绑定到一个变量,该变量的作用域只是catch语句块。
function test() {
var x = "var", result = [];
result.push(x);
try {
throw "exception";
} catch (x) {
x = "catch";
}
result.push(x);
return result;
}
test(); // ["var", "var"]
复制代码
提示
- 在代码块中的变量声明会被隐式地提升到封闭函数的顶部。
- 重声明变量被视为单个变量。
- 考虑手动提升局部变量的声明,从而避免混淆。