IIFE(立即执行函数)
在 JavaScript 中,IIFE 被广泛应用。
比如,我们经常能在一些 JavaScript 项目中,看到所有代码被包裹在一个 IIFE 中
1
2
3
(function(){
// 项目实现代码
}());
IIFE 的使用理由
使用 IIFE 的一个重要原因是,可以避免对外层作用域的污染。
因为IIFE的本质就是一个函数,我们在函数内部定义的所有变量、函数,均在函数本地生效,避免了跟其他 JavaScript 冲突。
声明变量务必使用 var(ES6 之后支持 let,const)。 因为非 strict mode 中,不使用 var 声明的变量,实际上是定义在全局作用域的。
此外还有一些有用的特性也是使用 IIFE 的理由之一,例如提供正确的 undefined
值:
1
2
3
4
5
6
(function(undefined){
// undefined 可能被重新赋值
// 无传递实参,确保了
// 形参 `undefined` 是
// 真正的 `undefined`
}());
当然利用这种模式,也可以往 IIFE 里面注入一些其他的依赖,比如全局对象等等。
IIFE 的执行原理
奥妙就在于 ()
上面,因为()
运算符内部必须是一个表达式。
所以,()
内部的函数不是一个函数声明,而是一个函数表达式,表达式的计算结果返回一个函数,然后立即被调用。
这跟下面的函数表达式一样道理(=
运算符右侧接受一个表达式):
1
2
3
4
var exprVal = function() {
return 'haha~'
}()
// exprVal === 'haha~'
IIFE 的其他写法
既然明白了 IIFE 的原理就是利用的函数表达式的性质,那么我们就可以有很多种写法了,例如
1
2
3
4
(function(){ /* 代码 */ })();
!function(){ /* 代码 */ }();
+function(){ /* 代码 */ }();
void function(){ /* 代码 */ }();
选择哪种写法基本取决于个人审美,不过惯例上使用括号的比较多。
但,不同的写法仍有一些其他的细微影响。
比如分号的使用,比如括号的方式,因为括号的多义性,如果前面还有内容,那么括号会被当作是一个函数调用,导致非期望的结果出现。
一个好的实践方式是,在括号、中括号等前面随手加上分号:
1
;(function(){ /* 代码 */ }())
这样可以避免 IIFE 前面的代码忘记加分号导致的问题。