细数JS之立即执行函数表达式(IIFE)

undefined

立即执行函数(IIFE)在编程中可以说是十分常见了。那么,借着两篇文章让这个概念彻底理解也是个不错的选择耶~~

什么是立即执行函数(WHAT)

由于IIFE函数并不罕见,所以直接抛出它的常见样子。

1
2
3
(function() {
// something
})();

没错,这就是立即执行函数。常用于防止局部变量泄露到全局范围。

为什么要这样写(WHY)

如果已经使用js的编程有一段时间了,你肯定已经熟悉这个样子的东西。(你可能只是不知道它叫IIFE)但是为什么一定要这么书写,它有没有更好的书写方式呢?

首先每个IIFE的核心就是函数(function).也就是这样的

1
2
3
function() {
// something
}

虽然这是核心,但是如果你的代码只有这一段东西,编译器会报错。因为它并不遵循函数声明的语言规则。那么很容易我们就能想到,声明函数的另一个方式——函数表达式。

1
var fun = function() {}

于是实现这个伎俩就很简单了。我们只需要通过将函数包含在括号内就能修复语法错误。就产生了这段代码。

1
(function() {})

那么因为它是一个匿名函数,你并没有办法用函数名调用执行它。这时候就能用()来使函数执行,这就有点像aa()。因为函数aa本质上也是一个函数表达式的引用。

没错,IIFE就是这么简单。那么按照这样的理解,我们很快就能类推出各种其他书写方式。因为当编译器看到了(,它就需要一个表达式,然后找相应的右括号),在这对括号里面的就是函数表达式。于是,我们可以这样写

1
2
3
(function() {
//somethind
}());

防御分号

另外,如果你看的源码比较多,你还可能看到这种书写方式。

1
2
3
;(function() {
//something
})();

这种分号叫做防御分号,用于防止在两个Javascript文件链接在一起时可能出现的问题。想象第一个文件包含这些代码:

1
var foo = bar

注意这里没有分号。再假设第二个javascrript文件没有包含防御分号。那么它们链接一起的结果是:

1
2
3
4
var foo = bar
(function() {
// ...
})();

乍一看好像没有问题,然而因为第一句没有分号的原因,编译器会将代码解析成这样,这样一看是不是就发现问题所在了。

1
2
3
var foo = bar(function() {
// ...
})();

而在前面加分号,是符合语法规则的,最多只被解析成一个空语句,能尽可能地避免开不必要的麻烦而没有副作用(唯一副作用可能就让你看起来不习惯)

ES6写法(不推荐)(不易于阅读)

1
2
3
() => {
// ...
}()

有什么作用(WAY)

函数作用域 VS 块级作用域

其实在ES6讨论作用域问题的立即执行函数显得没太多意义;ES6就能实现那个功能~~但是个人觉得没那么好看

1
2
3
4
5
{
let foo = "bar";
console.log(foo);
}
foo; // foo is not defined

闭包和私有数据

详细在闭包那篇中可以看到

变量重命名

直接贴范例吧~

1
2
3
(function($) {
// ...
})(jQuery);

捕获全局对象

JavaScript代码在不同环境执行时,你所使用的全局对象是不同的。当代码在浏览器运行时,全局对象是windows。但是在Node.js中,全局对象是global。由于在写通用的JavaScript代码时,你肯定不想硬编码这两个名字其中的任何一个,这时你就可以使用一种”包装”的方式就像下面这样:

1
2
3
(function(global) {
// ...
})(this);

压缩优化

这虽然更多是通过打包工具来实现,不过原生就是有这样的做法吧~~

1
2
3
(function(w, d, u) {
// ...
})(window, document);


参考文章:
Disassembling JavaScript’s IIFE Syntax
JavaScript立即执行函数表达式(IIFE)用例