变量的作用范围
在大多数编程语言中,变量的生命周期是“定义此变量的块(block)”。 但是在 JavaScript 中,变量的作用域却和函数息息相关,而不是大括号:
function func(x) {
console.log(tmp); // undefined
if (x < 0) {
var tmp = 100 - x; // (*)
...
}
}
(译注:很多程序员会觉得 tmp
变量的作用于是 if
块,其实不然,javascript 根本没有块作用域。)
上述代码引发的行为是:函数内部,在(*)处声明的变量 tmp
被移动到了函数的开头(赋值语句依然保留在原处)。 也就是说,实际上此段代码在 JavaScript 引擎中的运行时,看起来像这样:
function func(x) {
var tmp;
console.log(tmp); // undefined
if (x < 0) {
tmp = 100 - x;
...
}
}
但是,有一招可以把一个变量限制在一个块作用域,它被称为立即函数表达式(IIFE,发音为“iffy”)。
立即函数表达式:Immediately Invoked Function Expression。
下面,我们使用一个 IIFE,将 tmp
的作用域限制在包含它的 if
语句块中。
function func(x) {
console.log(tmp); // ReferenceError: tmp is not defined
if (x < 0) {
(function () { // open IIFE
var tmp = 100 - x;
...
}()); // close IIFE
}
}
我们在内部块的外面,写了一个函数,创建了一个新的作用域。 (译注:javascript 没有块作用域,OMG!。只有函数作用域,因此我们必须使用一个匿名函数,而且是立即执行的匿名函数创建了一个新的作用域。) 然后我们立即执行此函数。 tmp
仅仅存在于 IIFE 中。 需要注意的是围绕此 IIFE 的小括号是必须的。
如果没有环绕 IIFE 的小括号,函数成了:
function () {
var tmp = 100 - x;
}();
执行结果:
SyntaxError: Unexpected token (
(why?)
作者写道,
They lead to the function being interpreted as an expression, which is the only form in which it can be be immediately invoked.
我们需要在 IIFE 的开始和结束的地方,写上小括号,把函数解析成一个表达式。 这是把函数变成立即调用的唯一形式。
到底是不是唯一形式呢?
一、
(function () {
var tmp = 100 - x;
}());
二、
(function () {
var tmp = 100 - x;
})();