立即执行函数IIFE

到底什么是IIFE?

比较以下两种方式

var foo=function(){ /*code*/}
foo();

另一种错误的方法:

function(){}(); //Unexpected token

报错原因

JS代码解释的时候,遇到function关键字会默认把它当做一个函数声明,而不是函数表达式,如果没有把它显示表达成函数表达式就会报错。 没有函数名,所以会报错

加上函数名

function foo(){}() //unexpected token

加上了名字仍然报错,我们在一个表达式后面加上括号表示这个表达式立即执行。
但如果是一个语句后面加括号,则前后没有关系。以上代码等价于:

function foo(){}
();

相当于先声明了一个叫foo的函数,之后进行()内的表达式运算,但是()(分组操作符)内的表达式不能为空,所以报错。

IIFE正解

(function(){ /* code */ }());

成功,为什么? JS中,括号内部不能包含语句,当解释器对代码进行解释时,先碰到了(),然后碰到function关键字就会自动将()里面的代码识别为函数表达式而不是函数声明~~

IIFE其他更多的写法:

//常用写法
(function(){}());
(function(){})();

//括号 和 JS的一些操作符如(= && || , 等)可以在函数表达式和函数声明上消除歧义
//但是这种写法你不能交换两个的位置,解释器如果是先遇到function关键字就会报错了。
var i=fuction(){return 10;}();
true&&function(){/*code*/}();
0,function(){}();

一元运算符

!function(){}();
~function(){}();
-function(){}();
+function(){}();

new操作符

new function(){}
new function(){}() //带参数

通过以上的介绍,我们大概了解通过()可以使得一个函数表达式立即执行。
有的时候,我们实际上不需要使用()使之变成一个函数表达式,啥意思?比如下面这行代码,其实不加上()也不会保错:

var i = function(){ return 10; }();

道理还是一样,因为解释器先遇到=号了,就把后面的默认当做表达式处理了

但是好的代码规范

仍然是需要加上括号

var i = (function(){ return 10; }());

为了代码的可读性。

IIFE与闭包

IIFE可以配合闭包保存状态
在IIFE里面再定义一个函数,这个函数能够引用IIFE内部的变量和参数,利用这一点我们就可以利用IIFE锁住变量的状态了。

//执行后,我们得到了想要的结果,就是因为IIFE把循环变量的每个i都锁在内存中了,
//尽管for循环结束后i的值已经变了,但是闭包的原因,其实内存中还是有对这些变量的引用存在,就是说有副本存在。
var elems=document.getElementsByTagName( 'a' );
for ( var i = 0; i < elems.length; i++ ) {
    (function(lockedIndex){
        elems[i].addEventlistener('click',function(e){
            e.preventDefault();
            console.log('i am '+lockedIndex);
        },'false');
    })(i)
}

其实上面的代码中的lockedIndex换成i也是可以的,因为是在两个作用域(形参在内部函数作用域,而传入的i在外部IIFE的作用域)

函数声明和函数提升

有一种值得我们注意的做法:

if(condition){
    function sayHi(){
        alert('Hi');
    }
}else{
    function sayHi(){
        //other code
    }
}

这么做是有问题的,在ECMAScript中是无效语法,JS引擎会修改这个错误,转换成合理的状态。 但问题是浏览器尝试修正错误的做法并不一致。
大多数浏览器返回第二个声明,直接忽略condition

但是如果使用函数表达式,那么就没问题:

if(condition){
    sayHi=function (){
        alert('Hi');
    }
}else{
    sayHi=function (){
        //other code
    }
}

应该使用命名函数表达式,而不是callee

//arguments.callee 在严格模式下不通过
function factoral(num){
    if(num<=1){
        return 1;
    }else{
        return num*arguments.callee(num-1);
    }
}
var factoral=(function f(num){
    if(num<=1){
        return 1;
    }else{
        return num*f(num-1);
    }
})
IT文库 » 立即执行函数IIFE
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址