立即执行函数表达式 IIFE
23 Apr 2016
Reading time ~1 minute
Immediately-Invoked Function Expression (IIFE)
IIFE (Immediately-Invoked Function Expression) 是一个 JavaScript 函数 ,它会在定义时立即执行。
函数表达式 VS 函数声明
函数申明 (Function Declaration)
function test() {};
函数声明时必须有函数名。 我们也会看到_匿名函数_
function () {
}
函数表达式 (Function Expression)
var test = function() {};
函数表达式中的函数可以为匿名函数,也可以有函数名,但是该函数实际上不能直接使用,只能通过表达式左边的变量 test 来调用。
IIFE
首先执行一下下面的代码
function(){ /* code */ }(); // SyntaxError: Unexpected token (
报错了,这是为何?这是因为在javascript代码解释时,当遇到function关键字时,会默认把它当做是一个函数声明,而不是函数表达式,如果没有把它显视地表达成函数表达式,就报错了,因为_函数声明需要一个函数名_,而上面的代码中函数没有函数名。(以上代码,也正是在执行到第一个左括号(时报错,因为(前理论上是应该有个函数名的。)
(function(){ /* code */ }());
在javascript里,括号内部不能包含语句,当解析器对代码进行解释的时候,先碰到了(),然后碰到function关键字就会自动将()里面的代码识别为函数表达式而不是函数声明。所以上面的代码能立即执行,这种方式就叫IIFE
。
IIFE
并非只有上面的一种写法
// 最常用的两种写法
(function(){ /* code */ }()); // 推荐写法
(function(){ /* code */ })(); // 当然这种也可以
// 括号和JS的一些操作符(如 = && || ,等)可以在函数表达式和函数声明上消除歧义
// 如下代码中,解析器已经知道一个是表达式了,于是也会把另一个默认为表达式
// 但是两者交换则会报错
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
// 如果你不怕代码晦涩难读,也可以选择一元运算符
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();
// 你也可以这样
new function(){ /* code */ }
new function(){ /* code */ }() // 带参数
IIFE优点
总结有4点:提升性能、有利于压缩、避免冲突、依赖加载
- 减少作用域查找。通过匿名函数的参数传递常用全局对象window、document、jQuery,在作用域内引用这些全局对象。JavaScript解释器首先在作用域内查找属性,然后一直沿着链向上查找,直到全局范围。将全局对象放在IIFE作用域内提升js解释器的查找速度和性能。传递全局对象到IIFE的一段代码示例:
// Anonymous function that has three arguments
function(window, document, $) {
// You can now reference the window, document, and jQuery objects in a local scope
}(window, document, window.jQuery); // The global window, document, and jQuery objects are passed into the anonymous function
- 有利于压缩。既然通过参数传递了这些全局对象,压缩的时候可以将这些全局对象匿名为一个字符的变量名(只要这个字符没有被其他变量使用过)。如果上面的代码压缩后会变成这样:
// Anonymous function that has three arguments
function(w, d, $) {
// You can now reference the window, document, and jQuery objects in a local scope
}(window, document, window.jQuery); // The global window, document, and jQuery objects are passed into the anonymous function
- 避免全局命名冲突。当使用jQuery的时候,全局的window.jQuery对象 作为一个参数传递给$,在匿名函数内部你再也不需要担心$和其他库或者模板申明冲突。 正如James padolsey所说:
An IIFE protects a module’s scope from the environment in which it is placed.
- 通过传参的方式,可以灵活的加载第三方插件。
alcat2008
Dreamer, Practitioner, Incomplete Front-ender