IIFE是立即执行函数表达式(Immediately Invoked Function Expression)的缩写。它是一种特殊的函数调用方式,也是一种用来创建函数作用域的模式。
在JavaScript中,IIFE通过将函数用括号包裹,并在后面立即调用它来创建一个函数作用域。这样做的好处是可以在函数内部定义变量和函数,而不会对外部的全局作用域造成污染。
这里我最开始对「不会对外部的全局作用域造成污染」的理解有点问题,IIFE内部的声明、赋值等操作都不会影响到全局作用域,是一个完全独立的作用域。抱着想试试是否有这么神奇的用法,我跑了下下面的例子。
var a = 'global'
// test1 内部局部变量a,不会影响全局变量a
function test1() {
var a = 1
a = 'test1'
console.log(a)
}
test1()
console.log(a)
// test2 内部没有var,会直接修改全局变量a
function test2() {
a = 'test2'
console.log(a)
}
test2()
console.log(a)
// test3 内部局部变量a,不会影响全局变量a
;(function () {
var a = 'test3'
console.log(a)
})()
console.log(a)
// test4 内部没有var,会直接修改全局变量a
;(function () {
a = 'test4'
console.log(a)
})()
console.log(a)运行结果
test1
global
test2
test2
test3
test2
test4
test4其实从结果可以看出来,IIFE从作用域隔离的角度上来看其实和普通函数闭包没什么区别(其实本身也差不多是一个东西)。那么IIFE的作用到底是什么呢?其实要从比较实际的场景出发,在某次掘金冲浪中发现了这样一篇文章,解释了IIFE在没有 CommonJS 等技术时是如何实现模块化的。
原文链接:从构建产物洞悉模块化原理
以这个下面的HTML为例
<body>
<script src="./index.js"></script>
<script src="./home.js"></script>
<script src="./list.js"></script>
</body>其中 index.js 和 list.js 由 A 负责,home.js 由 B 负责。A 在 index.js 中声明
var name = 'foo'并在 list.js 中使用
console.log(name)结果却得到 name 变量变为了一个函数,而这是因为 B 在 home.js 中将 name 声明为了一个函数
function name(){
//...
}而这里如果 B 能够以 IIFE的方式来编写 home.js 则不会出现这种情况。因为 IIFE 在执行这段JS时就会立即形成闭包来进行隔离保护,甚至都不需要一个具名的方法来运行。虽然这种方式在现在看来还存在着很多提升空间,但在当时的环境下解决了全局变量污染的问题也算是给予了 JS 丰富的插件生态的发展空间(个人认为)。