介紹IIFEjavascript
- IIFE的性能
- 使用IIFE的好處
- IIFE最佳實踐
- jQuery優化
在Bootstrap源碼(具體請看《Bootstrap源碼解析》)和其餘jQuery插件常常看到以下的寫法: html
+function ($) { }(window.jQuery);
這種寫法稱爲:java
IIFE (Imdiately Invoked Function Expression 當即執行的函數表達式)。jquery
來分析這段代碼git
先弄清 函數表達式(function expression)和 函數聲明(function declaration)的區別:github
函數表達式 Function Expression express
var test = function() {};
函數申明 Function Declaration ecmascript
function test() {}
函數表達式中的函數能夠爲匿名函數,也能夠有函數名,可是該函數實際上不能直接使用,只能經過表達式左邊的變量 a 來調用。 模塊化
函數聲明時必須有函數名。 函數
function a(){ alert('Function declaration'); } a();
這是一個匿名函數。
你也許注意到匿名函數在console下會報錯。console的執行和報錯以下:
function(){}
經過一元操做符+變成了函數表達式。也可使用 - ~ !等其餘一元運算符或者括號,目的是爲了引導解析器,指明運算符附近是一個表達式。如下是三種經典方式 :
+function () { }; (function () { }); void function() { };
函數表達式經過 末尾的() 來調用並運行。就是一個IIFE。
+function () { }(); (funtion () { })();
代碼性能
運算符:+加 / -減 / ! 邏輯非 / ~位取反,返回NaN(Not A Number)。
「()」組運算符:返回表達式的執行結果undefined。
void:按運算符結合語句執行,返回 undefined。
這幾種的性能對比結果:
可見+性能最差(在Firefox下差距更明顯),其餘幾種都差很少。不過IIFE只執行一遍,對js執行效率的影響特別小,使用哪一種仍是看我的愛好
傳參,爲了不$與其餘庫或者模板申明衝突,window.jQuery 做爲參數傳遞。
+function (x) { console.log(x); }(3); +function ($) { }(window.jQuery);
使用IIFE的好處
總結有4點:提高性能、有利於壓縮、避免衝突、依賴加載
一、減小做用域查找。使用IIFE的一個微小的性能優點是經過匿名函數的參數傳遞經常使用全局對象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
二、有利於壓縮。另外一個微小的優點是有利於代碼壓縮。既然經過參數傳遞了這些全局對象,壓縮的時候能夠將這些全局對象匿名爲一個字符的變量名(只要
這個字符沒有被其餘變量使用過)。若是上面的代碼壓縮後會變成這樣:
三、避免全局命名衝突。當使用jQuery的時候,全局的window.jQuery對象 做爲一個參數傳遞給$,在匿名函數內部你不再須要擔憂$和其餘庫或者模板申明衝
突。 正如James padolsey所說:
An IIFE protects a module’s scope from the environment in which it is placed.
四、經過傳參的方式,能夠靈活的加載第三方插件。(固然使用模塊化加載更好,這裏不考慮。)舉個例子,若是a頁面須要使用KindEditor,a.html引入kindeditor.js
和 a.js
你可能會這麼寫 a.js:
$(function() { var editor KindEditor.ready(function(K) { editor = K.create('textarea[data-name="kindeditor"]', { resizeType : 1 }) }) })
b頁面不須要使用Kindeditor,沒有引入kindeditor.js。可是在合併JS代碼後,b頁面也會執行a.js中的代碼,頁面報錯Uncaught ReferenceError: KindEditor is not defined。
也就是b頁面執行了KindEditor,難道全部頁面都要加載Kindeditor源文件?
能夠這麼修改a.js,將KindEditor變量參數化,經過給當即執行的函數表示式的參數賦值,那麼其餘頁面都不須要加載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) { // Calls the second IIFE and locally passes in the global jQuery, window, and document objects library(window, document, window.jQuery); } // Locally scoped parameters (function (window, document, $) { // Library code goes here }));
這種IIFE模式清晰的展現了傳遞了哪些全局對象到你的IIFE中,不須要滾動到長文檔的最後。
jQuery優化
一段看上去寫法有點像的代碼。大部分項目用這段代碼作做用域,這段代碼會在DOM加載完成時初始化jQuery代碼。
$(function(){ });
這種寫法等同於
$(document).ready(function(){ // 在DOM加載完成時初始化jQuery代碼。 });