在 jQuery 及其插件中经常看到如下的写法:
+function($) {}(window.jQuery);
这种写法称为:
IIFE (Immediately Invoked Function Expression 立即执行的函数表达式)。
函数表达式与函数声明
函数表达式 Function Expression:
var test = function() {};
函数声明 Function Declaration:
function test() {};
函数表达式中的函数可以为匿名函数,也可以有函数名,但该函数实际上不能直接使用,只能通过表达式左边的变量 fl
来调用:
var fl = function() {
console.log("Function expression");
};
var cc = new fl();
函数声明时必须有函数名:
function fl() {
console.log("Function Declaration");
}
fl();
匿名函数在 console
下会报错。console
的执行和报错如下:
SyntaxError: Unexpected token (
通过一元操作符 +
变成了函数表达式。也可以使用 -
、~
、!
等其他一元运算符或者括号,目的是为了引导解析器,指明运算符附近是一个表达式。以下是三种经典方式:
+function() {};
(function() {});
void function() {};
函数表达式通过末尾的 ()
来调用并运行,就是一个 IIFE。
+function() {} ();
(function() {}) ();
为了避免 $
与其他库或者模板声明冲突,window.jQuery
作为参数传递:
+function($) {
}(window.jquery);
使用 IIFE 的好处
-
减少作用域查找
使用 IIFE 的一个微小的性能优势是通过匿名函数的参数传递常用全局对象window
、document
、jQuery
,在作用域内引用这些全局对象。JavaScript 解释器首先在作用域内查找属性,然后一直沿着链向上查找,直到全局范围。将全局对象放在 IIFE 作用域内提升 JavaScript 解释器的查找速度和性能:
function(window, document, $) { }(window, document, window.jQuery);
-
有利于压缩
另一个微小的优势是有利于代码压缩。既然通过参数传递了这些全局对象,压缩的时候可以将这些全局对象匿名为一个字符的变量名(只要这个字符没有被其他变量使用过)。如果上面的代码压缩后会变成这样:
function(w, d, $) { }(window, document, window.jQuery);
-
避免全局命名冲突
当使用 jQuery 的时候,全局的window.jQuery
对象作为一个参数传递给$
,在匿名函数内部再也不需要担心$
和其他库或者模板声明冲突。 -
通过传参的方式,可以灵活地加载第三方插件
举个例子,如果a.html
页面需要使用 KindEditor:$(function() { var editor; KindEditor.ready(function(K) { editor = K.create('textarea[data-name="kindeditor"]', { resizeType: 1 }); }); });
如果
b.html
不需要使用 KindEditor,没有引入kindeditor.js
,在合并 JS 代码后,b.html
页面会报错:Uncaught ReferenceError: KindEditor is not defined
修改
a.js
,将KindEditor
变量参数化,通过给立即执行的函数表示式的参数赋值:+function(KindEditor) { var editor; if (KindEditor) { KindEditor.ready(function(K) { editor = K.create('textarea[data-name="kindeditor"]', { resizeType: 1 }); }); } }(KindEditor || undefined);
IIFE 的可读性问题
反对使用 IIFE 的其中一个理由是可读性差。如果有大量的 JavaScript 代码都在一段 IIFE 里,想查找 IIFE 传递的实际参数值,必须滚动到代码最后。
更可读的模式:
(function(library) {
library(window, document, window.jQuery);
}(function(window, document, $) {
}));
jQuery 优化
大部分项目用这段代码做作用域,在 DOM 加载完成时初始化 jQuery 代码:
$(function() {});
// 等价于
$(document).ready(function() {
// 在 DOM 加载完成时初始化 jQuery 代码。
});
区别于:
$(window).load(function() {
// 在图片等媒体文件加载完成时,初始化 jQuery 代码。
});
结合 IIFE 的最佳实践:
+function() {
$(function() {
});
}(window.jQuery);
更好的写法:
+function(yourcode) {
yourcode(window.jquery, window, document);
}(function($, window, document) {
$(function() {
});
});
评论区