最近,我已經閱讀了不少Javascript,而且一直注意到整個文件都像下面這樣封裝在要導入的.js文件中。 html
(function() { ... code ... })();
爲何這樣作而不是使用一組簡單的構造函數呢? html5
這就是所謂的關閉。 它基本上將代碼密封在函數內部,以便其餘庫不會干擾它。 這相似於以編譯語言建立名稱空間。 jquery
例。 假設我寫: web
(function() { var x = 2; // do stuff with x })();
如今其餘庫沒法訪問我在庫中建立的變量x
。 canvas
瀏覽器中的JavaScript實際上僅具備兩個有效範圍:函數範圍和全局範圍。 瀏覽器
若是變量不在函數範圍內,則在全局範圍內。 並且全局變量一般是很差的,所以這是一種將庫的變量保留給本身的構造。 閉包
一般是到名稱空間(請參閱下文)並控制成員函數和/或變量的可見性。 能夠將其視爲對象定義。 jQuery插件一般是這樣寫的。 app
在Javascript中,您能夠嵌套函數。 所以,如下是合法的: 函數
function outerFunction() { function innerFunction() { // code } }
如今,你能夠調用outerFunction()
但的可見性innerFunction()
被限制的範圍outerFunction()
這意味着它是專用於outerFunction()
它基本上遵循與Javascript中的變量相同的原理: 性能
var globalVariable; function someFunction() { var localVariable; }
相應地:
function globalFunction() { var localFunction1 = function() { //I'm anonymous! But localFunction1 is a reference to me! }; function localFunction2() { //I'm named! } }
在上述狀況下,您能夠在任何地方調用globalFunction()
,但不能調用localFunction1
或localFunction2
。
在編寫(function() { ... code ... })()
,您正在作的是在函數文字內部編寫代碼(這意味着整個「對象」其實是一個函數)。 以後,您將自動調用該函數(final ()
)。 所以,正如我前面提到的,此方法的主要優勢是您能夠擁有私有方法/函數和屬性:
(function() { var private_var; function private_function() { //code } })()
在第一個示例中,globalFunction()是能夠調用以訪問公共功能的公共函數,可是在上面的示例中,您如何調用它? 在這裏,自調用功能使代碼在啓動時自動運行。 就像您能夠添加initMyStuff(); 到任何.js文件的頂部,它將自動做爲全局範圍的一部分運行,該自調用函數也將自動運行,儘管因爲它是一個未命名的函數,所以不能像initMyStuff()那樣屢次調用。
整潔的事情是,您還能夠在內部定義事物並將其公開給外部世界(例如,命名空間的示例,所以您基本上能夠建立本身的庫/插件):
var myPlugin = (function() { var private_var; function private_function() { } return { public_function1: function() { }, public_function2: function() { } } })()
如今您能夠調用myPlugin.public_function1()
,但沒法訪問private_function()
! 所以很是相似於類定義。 爲了更好地理解這一點,我建議如下連接以供進一步閱讀:
編輯
我忘了提。 在final ()
,您能夠傳遞您想要的任何內容。 例如,當您建立jQuery插件時,您像這樣傳遞jQuery
或$
:
(function(jQ) { ... code ... })(jQuery)
所以,您在這裏要作的是定義一個帶有一個參數的函數(稱爲jQ
,一個局部變量,而且僅對該函數已知)。 那麼你的自我調用函數,並傳遞一個參數(也稱爲jQuery
,可是這一次是從外面的世界,並以實際的jQuery自身的引用)。 這樣作並無緊迫的需求,可是有一些優勢:
早先,我描述了這些函數如何在啓動時自動運行,可是若是它們自動運行,誰傳入參數? 該技術假定全部參數都定義爲全局變量。 所以,若是未將jQuery定義爲全局變量,則此示例將不起做用,而且因爲咱們的示例是匿名函數,所以沒法以任何其餘方式調用。 您可能會猜到,jquery.js在初始化期間所作的一件事是定義了一個'jQuery'全局變量,以及它更爲著名的'$'全局變量,它使該代碼在包含jquery.js以後能夠工做。
除了將變量保留在本地以外,一種很是方便的用法是在使用全局變量編寫庫時,能夠給它一個較短的變量名,以在庫中使用。 它常常用於編寫jQuery插件,由於jQuery容許您使用jQuery.noConflict()禁用指向jQuery的$變量。 若是禁用它,您的代碼仍然可使用$而且只要您這樣作就不會中斷:
(function($) { ...code...})(jQuery);
您也能夠將函數閉包用做較大表達式中的數據 ,就像這種肯定瀏覽器對某些html5對象支持的方法同樣。
navigator.html5={ canvas: (function(){ var dc= document.createElement('canvas'); if(!dc.getContext) return 0; var c= dc.getContext('2d'); return typeof c.fillText== 'function'? 2: 1; })(), localStorage: (function(){ return !!window.localStorage; })(), webworkers: (function(){ return !!window.Worker; })(), offline: (function(){ return !!window.applicationCache; })() }