立即执行函数IIFE

来源:互联网 发布:淘宝实名认证可以改吗 编辑:程序博客网 时间:2024/05/21 19:40

到底什么是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);    }})
0 0
原创粉丝点击