JavaScript 作用域几乎只有两种类型:
-
每个 var 声明的作用域与最直接的封闭函数相关联
-
如果 var 声明没有封闭函数,则它是全局作用域
因此,除函数之外的任何块都不会创建新的作用域。这解释了为什么 for 循环会覆盖外部作用域变量:
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5
改用函数:
var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10
在第一个例子中,没有块作用域,因此最初声明的变量被覆盖。在第二个例子中,由于函数而产生了新的作用域,因此最初声明的变量被隐藏,并且没有被覆盖。
这就是你在 JavaScript 作用域方面需要知道的几乎全部内容,除了:
所以你可以看到 JavaScript 作用域实际上非常简单,尽管并不总是直观的。需要注意以下几点:
-
var 声明被提升到作用域的顶部。这意味着无论 var 声明发生在哪里,对于编译器来说,var 本身就像发生在顶部一样
-
同一作用域内的多个 var 声明被合并
所以这个代码:
var i = 1;
function abc() {
i = 2;
var i = 3;
}
console.log(i); // outputs 1
相当于:
var i = 1;
function abc() {
var i; // var declaration moved to the top of the scope
i = 2;
i = 3; // the assignment stays where it is
}
console.log(i);
这看起来可能违反直觉,但从命令式语言设计者的角度来看,这是有道理的。