说到立即调用函数就要提到函数,但是函数这一部分请自行查看文档 JavaScript 指南 函数 JavaScript 参考 函数
使用
通常有两种写法:
1
(function(){ /* code */ }());
1 |
(function(){ /* code */ })(); |
这里面使用了圆括号运算符,那么具体是什么原因,我们来看一下。
解析
在 Javascript 中,圆括号()是一种运算符,跟在函数名之后,表示调用该函数。
1
2
3
4
5
function print(params) {
console.log(params);
}
print('print test');
如果我们为了减少代码的书写量,合并起来写。
1
2
3
function print(params) {
console.log(params);
}('print test')
代码是可以执行的,而且和上面一段代码是等价的;如果我的代码是仅仅执行一次,那就使用匿名函数去执行。
1
2
3
4
5
function(params) {
console.log(params);
}('print test')
// Chrome: Uncaught SyntaxError: Unexpected token (
// Firefox: SyntaxError: function statement requires a name
会提示错误,而且Chrome和Firefox提示的错误信息还不相同;出现这个问题我们要先知道定义函数的方式:
-
函数声明
1
2
3
4
5function print(params) {
console.log(params);
}
// 执行函数
print('print test'); -
函数表达式
1
2
3
4
5
6// 匿名函数创建
var print = function (params) {
console.log(params);
}
// 执行函数
print('print test');1
2
3
4
5
6// 具名函数创建,这种方式可以在函数内部方便的调用自身
var print = function print(params) {
console.log(params);
}
// 执行函数
print('print test');1
2
3
4
5
6//
var print = (params) => {
console.log(params);
}
// 执行函数
print('print test');
可以看到最后在指向函数的时候都是有一个函数名,通过函数名称执行函数。
同时我们还要知道function这个关键字即可以当作语句,也可以当作表达式。如果function关键字出现在行首,一律解释成语句。因此,JavaScript引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
上面出现错误的代码既不是一个正确的函数声明,也不是一个函数表达式,所以就报错了。
解决方法就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面,也就是我们开篇提到的两个方法。
他们都是以圆括号开头,引擎就会认为后面跟的是一个表示式,而不是函数定义语句,所以就避免了错误。这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。
如果有多个IIFE则每一个IIFE后面都要有;,可能会报错。
拓展
任何让解释器以表达式来处理函数定义的方法,都能产生同样的效果
1
2
3
4
5
6
7
8
9
10
11
12
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
!function () { /* code */ }();
~function () { /* code */ }();
-function () { /* code */ }();
+function () { /* code */ }();
// new 关键字
new function(){ /* code */ }
new function(){ /* code */ }() // 只有传递参数时,才需要最后那个圆括号。
总结
IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。
1
2
3
(function () {
statements
})();
这是一个被称为 自执行匿名函数 的设计模式,主要包含两部分。第一部分是包围在 圆括号运算符 () 里的一个匿名函数,这个匿名函数拥有独立的词法作用域。这不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域。
第二部分再一次使用 () 创建了一个立即执行函数表达式,JavaScript 引擎到此将直接执行函数。
JQuery 也使用此方式
1
2
3
(function( window, undefined) {
// jquery code
})(window)
IIFE结合闭包的是一种比较好的应用,通过闭包实现了隔离了作用域,还可以立即执行。这是模块化模式
参考
http://benalman.com/news/2010/11/immediately-invoked-function-expression/
https://www.cnblogs.com/mrray1105/p/9150933.html
https://developer.mozilla.org/zh-CN/docs/Glossary/%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8C%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Errors/Unnamed_function_statement
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Functions
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions
http://javascript.ruanyifeng.com/grammar/function.html#toc23
https://www.cnblogs.com/tomxu/archive/2011/12/31/2289423.html
https://segmentfault.com/a/1190000003902899