深入理解javascript之IIFE
IIFE的全称是Immediately-invoked Function Expression,立即执行函数表达式。
在讲IIEF之前,我们首先需要区分函数表达式和函数声明。
var test = function(){};
这个叫做函数表达式。
function test(){};
这个叫做函数声明。
函数表达式中的函数可以为匿名函数,也可以有函数名,但是该函数实际上不能直接使用,只能通过表达式左边的变量test来调用。
如果我们要调用函数表达式,通过以下方式即可:
var test = function(){};
test();
如果我们直接使用匿名函数:
function(){}()//SyntaxError:Unexpected token(
就会报错,这是因为浏览器引擎在解释javascript时,遇到function关键字时,会默认把它当做一个函数声明,而不是函数表达式。而函数声明如我们上面所说,需要一个函数名,所以浏览器会认为上面的代码为匿名函数声明,所以报错。
但是,这里需要注意,即使我们给它一个函数名,它依然会报错:
function test(){}();//SyntaxError:Unexpected token )
为什么会这样呢?在一个函数表达式后面加上括号,表示该表达式立即执行。但是如果是在一条语句后面加上括号,那么该括号只是用来控制优先级的。所以上面的代码相当于声明了一个函数,然后执行()语句,但是()中内容为空,所以报错。
所以最后的解决办法就是写成如下形式:
(function (){}());
这样就不会报错了,因为当解释器遇到(后,会认为其中的function不是函数声明而是函数表达式,所以就成功啦。
IIFE可以带来块状作用域效果:
var a = 2;
(function IIFE(){
var a = 3;
console.log( a ); // 3
})();
console.log( a ); // 2
当然,还有其他多种方法立即执行匿名函数:
(function(){})();
void function(){}(); //使用void
!function(){}();//使用一元运算符
~function(){}();
-function(){}();
+function(){}();
在Bootstrap源码中就使用了大量的IIFE:
+function ($) { }(window.jQuery);
最后,注意一下函数表达式和函数声明的使用。请看代码:
if (true) {
var foo = function(){
document.write( "1" );
}
}
else {
var foo = function(){
document.write( "2" );
}
}
foo();//1
输出结果为1,这个很好理解,那么我们调整一下执行foo的位置呢:
foo();//undefined
if (true) {
var foo = function(){
document.write( "1" );
}
}
else {
var foo = function(){
document.write( "2" );
}
}
这里就是未定义。这是由于变量提升。javascript解释器在解释代码时会将变量声明先提升到块级作用域最前端,也就是这个样子:
var foo;
foo();//undefined
if (true) {
foo = function(){
document.write( "1" );
}
}
else {
foo = function(){
document.write( "2" );
}
}
那么我们看看使用函数声明时的结果:
if (true) {
function foo() {
document.write( "1" );
}
}
else {
function foo() {
document.write( "2" );
}
}
foo(); // 2
咦,这里怎么又输出2了呢?原来函数声明和变量一样,都有一个提升的过程,而和函数表达式只会提升声明不一样,函数声明即会提升声明,也会提升定义,所以第二个foo的定义把第一个foo给替换掉了。