立即执行函数表达式 —— IIFE
无论阅读源码还是日常开发当中常常会见到 (function(){ ... })()
这种形式的表达式,它就是 IIFE,立即执行函数表达式(Immediately Invoked Function Expression)。除了上述的结构以外还有另一种形式同样非常常见 (function() { ... }())
。下面介绍 IIFE 常见的应用。
避免污染全局作用域
IIFE 最常见的应用可见于各种前端 Javascript 库当中,避免库中定义的变量污染全局作用域。
1 | // jQuery 3.3.1 |
1 | // lodash 4.17.5 |
上述两个例子分别是 jQuery 和 lodash 使用 IIFE 的例子,可以看到除了避免全局作用域被污染以外,两者都利用 IIFE 的参数将全局的变量传入函数作用域当中,jQuery 还统一将不同环境当中的全局作用域通通重命名为 global
。
另外,除了传入全局变量以外,还可以传入任何你想传入的东西,如 jQuery 代码当中就传入了一个名为 factory
的函数。另一个常见传入的就是 undefined
,避免 undefined
被覆盖而导致的异常。
1 |
|
闭包
在学习 JavaScript 作用域知识的时候常常见到下面这样的问题:
定时输出数字 1~5,但结果输出的全部是6.
1 | for (var i = 1; i <= 5; i++) { |
又如希望点击列表元素输出相应数字,结果输出的全部是6.
1 | <div id="list"> |
1 | var lists = document.querySelectorAll('#list li') |
由于回调函数是在循环结束之后才被执行,在语义上我们感觉是每次回调函数绑定的是当时循环的 i
,而实际上所有的匿名函数都是共用一个 i
的引用,所以会发现输出的都是6,并不是原来希望的结果。
为了解决这个问题,我们可以使用 IIFE 来创建一个作用域来捕获当时循环的 i
。
1 | for (var i = 1; i <= 5; i++) { |
1 | var lists = document.querySelectorAll('#list li') |
当然,上述只是用来说明 IIFE 的作用,更好的方案应该使用 let
关键字以及不在每个元素绑定事件而是使用事件代理。
同样利用 IIFE 结合闭包可以实现简单的单例模式。
1 | var foo = (function CoolModule() { |
最后,IIFE 给我们提供了非常强大的功能,使用的时候最重要的是理解 IIFE 包装了一个函数作用域,使得外部作用域无法访问函数内的内容,同时通过访问函数内部以各种形式暴露的函数形成闭包,从而实现各种强大的功能。
参考
本文地址 http://blog.acwong.org/2018/04/18/introduction-to-IIFE/