一、立即执行函数(IIFE)
立即执行函数就是在声明一个匿名函数时,立即调用这个函数。格式一共有三种写法,举个栗子:
//第一种格式: (function(a,b){ alert(a+b); }(15,23)); //第二种格式 (function(a,b){ alert(a*b) })(5,12); //第三种格式(不常用) +function(a,b){ alert(a*b) }(9,10)
二、立即执行函数的作用
立即执行函数会创建一个独立的作用域,让外部无法访问作用域内部的变量,从而避免变量污染。并且该函数只会执行一次,执行后自动被垃圾回收。
举个栗子:经典面试题——如何让下面这段代码输出0-5
for(var i = 0; i < 6; i++){ setTimeout(function(){ console.log(i) },1000) }
我们可以使用立即执行函数来解决这个问题
for(var i = 0; i < 6; i++){ setTimeout((function(i){ console.log(i) })(i),1000) }
上面的代码之所以输出的结果是0到5,而不是6个6,是因为我们每次都将for循环中的i单独赋值给了for循环内部的i。 每一次for循环内i值变化的时候,我们都立即执行函数在for循环内部创建了一个独立的作用域,所以最终输出的结果是0到5。
三、立即执行函数的好处
1、立即执行函数模式被广泛使用,它可以帮你封装大量的工作而不会在背后遗留任何全局变量。
2、定义的所有变量都会成员立即执行函数的局部变量,所以你不用担心这些临时变量会污染全局空间。
3、这种模式经常被使用在书签工具(bookmarklets)中,因为书签工具在任何页面上运行并且保持全局命名空间干净是非常必要的;
4、这种模式也可以让你将独立的功能封装在自包含模块中。
5、可以将这些代码封装进一个立即执行函数中,并且确保页面没有它的情况下也能正常工作。
6、可以添加更多的加强模块,移除它们,单独测试它们,允许用户去禁用它们等等。
四、立即执行函数和闭包的区别
立即执行函数和闭包没有关系,虽然两者会经常结合在一起使用,但两者有本质的不同:
立即执行函数只是函数的一种调用方式,只是声明完之后立即执行,这类函数一般都只是调用一次(可用于单例对象上),调用完之后会立即销毁,不会占用内存。
闭包则主要是让外部函数可以访问内部函数的作用域,也减少了全局变量的使用,保证了内部变量的安全,但因被引用的内部变量不能被销毁,增大了内存消耗,使用不当易造成内存泄露。
五、立即执行函数与闭包常结合示例
let single = (function () { let name = "小明"; let age = 20; return { getName: function () { return name; }, getAge: function () { return age; } } })(); console.log(single.getName()); //小明 console.log(single.getAge()); //20
给对象创建了私有变量name、age又对外提供了获取的方法,典型的自执行函数和闭包结合使用的示例
六、立即执行函数使用场景
1、代码在页面加载完成之后,不得不执行一些设置工作,比如时间处理器,创建对象等等。
2、所有的这些动作只需要执行一次,比如只需要显示一个事件。
3、将代码包裹在它的局部作用域中,不会让任何变量泄漏成全局变量。
七、笔试题
请写出下面的代码执行后会输出什么?
var a=1; (function a(){ console.log(1,a); var a=2; console.log(2,a); delete a; console.log(3,a); })(); console.log(a);
分析:由于立即执行函数的特性,会先执行函数内部的代码,再执行外层的console语句。立即执行函数内部有var a=2,所以存在变量提升,那么函数内部最开始打印的就是1 undefined,然后a被赋值为2,接着打印出2 2,然后使用delete关键字删除a,由于delete用于删除对象的属性,但不能删除变量,也不能删除定义的函数,事实上,该操作返回的是false,所以不影响函数内最后一个console语句的输出,打印出3 2,外层console打印出4 1,因为立即执行函数的作用域是独立的且函数执行之后会立即被垃圾回收,所以外层的console打印的是全局的a,所以是1.