在JavaScript中,您在使用变量之前先声明它们:var
> var x;
> x
未定义
> y
ReferenceError:y未定义
您可以使用一个var 语句来声明和初始化几个变量:
var x = 1, y = 2, z = 3;
但是我建议每个变量使用一个语句(原因在Syntax中进行了解释)。因此,我将前面的语句重写为:
var x = 1;
var y = 2;
var z = 3;
由于提升(请参见变量提升),通常最好在函数的开头声明变量。
变量是函数范围的
变量的范围始终是完整的功能(与当前块相反)。例如:
function foo() {
var x = -512;
if (x < 0) { // (1)
var tmp = -x;
...
}
console.log(tmp); // 512
}
我们可以看到变量tmp不限于从第(1)行开始的块。它存在直到函数结束。
变量被吊起
每个变量声明都是悬挂的:该声明将移至该函数的开头,但保留的赋值将保留。例如,请考虑以下函数中第(1)行中的变量声明:
function foo() {
console.log(tmp); // undefined
if (false) {
var tmp = 3; // (1)
}
}
在内部,前面的函数是这样执行的:
function foo() {
var tmp; // hoisted declaration
console.log(tmp);
if (false) {
tmp = 3; // assignment stays put
}
}
关闭
每个功能 即使它离开了创建它的作用域,它仍然与围绕它的函数的变量保持联系。例如:
function createIncrementor(start) {
return function () { // (1)
start++;
return start;
}
}
从第(1)行开始的函数会离开其创建时所在的上下文,但仍保持与以下版本的实时连接start:
> var inc = createIncrementor(5);
> inc()
6
> inc()
7
> inc()
8
一个封闭的功能加上其周边范围的变量的连接。因此,createIncrementor()返回的是封闭。
IIFE模式:引入新的范围
有时您想引入一个新的 变量作用域-例如,防止变量成为全局变量。在JavaScript中,您不能使用块来这样做。您必须使用一个函数。但是,存在一种以块状方式使用功能的模式。它称为IIFE(立即调用的函数表达式,发音为“ iffy”):
(function () { // open IIFE
var tmp = ...; // not a global variable
}()); // close IIFE
确保完全按照显示的方式键入前面的示例(注释除外)。IIFE是定义后立即调用的函数表达式。在函数内部,存在新的作用域,以防止其tmp成为全局变量。有关IIFE的详细信息,请咨询通过IIFE引入新范围。
IIFE用例:通过关闭无意间共享
闭包保持它们与外部变量的连接,有时这不是您想要的:
var result = [];
for (var i=0; i < 5; i++) {
result.push(function () { return i }); // (1)
}
console.log(result[1]()); // 5 (not 1)
console.log(result[3]()); // 5 (not 3)
第(1)行中返回的值始终是的当前值i,而不是创建函数时的值。循环完成后,i值为5,这就是数组中所有函数都返回该值的原因。如果希望第(1)行中的函数接收的当前值的快照,则i可以使用IIFE:
for (var i=0; i < 5; i++) {
(function () {
var i2 = i; // copy current i
result.push(function () { return i2 });
}());
}