摘要:打開源碼,首先你會(huì)看到這樣的代碼結(jié)構(gòu)這是一個(gè)自調(diào)用匿名函數(shù)。模式,是自執(zhí)行函數(shù)的高級(jí)模式,可以非常方便的在各個(gè)匿名閉包中以全局對(duì)象調(diào)用閉包函數(shù)。
打開jQuery源碼,首先你會(huì)看到這樣的代碼結(jié)構(gòu):
(function(window,undefined ){
//
})();
這是一個(gè)自調(diào)用匿名函數(shù)。什么東東呢?在第一個(gè)括號(hào)內(nèi),創(chuàng)建一個(gè)匿名函數(shù);第二個(gè)括號(hào),立即執(zhí)行
為什么要?jiǎng)?chuàng)建這樣一個(gè)“自調(diào)用匿名函數(shù)”呢?
通過定義一個(gè)匿名函數(shù),創(chuàng)建了一個(gè)“私有”的命名空間,該命名空間的變量和方法,不會(huì)破壞全局的命名空間。這點(diǎn)非常有用也是一個(gè)JS框架必須支持的功能,jQuery被應(yīng)用在成千上萬(wàn)的JavaScript程序中,必須確保jQuery創(chuàng)建的變量不能和導(dǎo)入他的程序所使用的變量發(fā)生沖突。
接下來(lái)看看在 自調(diào)用匿名函數(shù) 中都實(shí)現(xiàn)了什么功能,按照代碼順序排列:
(function( window, undefined ) {
// 構(gòu)造jQuery對(duì)象 var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context, rootjQuery ); } // 工具函數(shù) Utilities // 異步隊(duì)列 Deferred // 瀏覽器測(cè)試 Support // 數(shù)據(jù)緩存 Data // 隊(duì)列 queue // 屬性操作 Attribute // 事件處理 Event // 選擇器 Sizzle // DOM遍歷 // DOM操作 // CSS操作 // 異步請(qǐng)求 Ajax // 動(dòng)畫 FX // 坐標(biāo)和大小 window.jQuery = window.$ = jQuery;
})(window);
匿名函數(shù)從語(yǔ)法上叫函數(shù)直接量,JavaScript語(yǔ)法需要包圍匿名函數(shù)的括號(hào),事實(shí)上自調(diào)用匿名函數(shù)有兩種寫法:
(function() {
console.info( this ); console.info( arguments );
}( window ) );
(function() {
console.info( this ); console.info( arguments );
})( window );
為什么要傳入window呢?
通過傳入window變量,使得window由全局變量變?yōu)榫植孔兞浚?dāng)在jQuery代碼塊中訪問window時(shí),不需要將作用域鏈回退到頂層作用域,這樣可以更快的訪問window;這還不是關(guān)鍵所在,更重要的是,將window作為參數(shù)傳入,可以在壓縮代碼時(shí)進(jìn)行優(yōu)化,看看jquery-1.6.1.min.js: (function(a,b){})(window); // window 被優(yōu)化為 a
通過以上的介紹,我們大概了解通過()可以使得一個(gè)函數(shù)表達(dá)式立即執(zhí)行。
匿名函數(shù)作為一個(gè)“容器”,“容器”內(nèi)部可以訪問外部的變量,而外部環(huán)境不能訪問“容器”內(nèi)部的變量,
所以 ( function(){…} )() 內(nèi)部定義的變量不會(huì)和外部的變量發(fā)生沖突,俗稱“匿名包裹器”或“命名空間”。
(function () {
// ... 所有的變量和function都在這里聲明,并且作用域也只能在這個(gè)匿名閉包里 // ...但是這里的代碼依然可以訪問外部全局的對(duì)象
}());
同下面
(function () {/ 內(nèi)部代碼 /})();
通俗的講,()就是用來(lái)求值的,因此這個(gè)()任何時(shí)候都不能為空,因?yàn)樗且?jì)算的。函數(shù)解析它只會(huì)解析到 {}為止,不會(huì)解析到 ()的。
把表達(dá)式放在()中會(huì)返回表達(dá)式的值; 把函數(shù)放在()中會(huì)返回函數(shù)本身;(function(){}()); 如果()緊跟在函數(shù)后面,就是表示在調(diào)用函數(shù),即對(duì)函數(shù)求值:(function(){})();
(function() {
//自執(zhí)行函數(shù)中的內(nèi)部變量,外部是無(wú)法訪問的 var name = "kevin";
})( window );
name //undefined,無(wú)法獲取name的值
代碼在運(yùn)行過程中,會(huì)優(yōu)先解析 【巳聲明的函數(shù)】;
而函數(shù)表達(dá)式是當(dāng)執(zhí)行到它時(shí),才會(huì)解析; 匿名函數(shù)是不會(huì)多帶帶寫的,因此它的執(zhí)行是需要其它函數(shù)的調(diào)用,通??吹降哪涿瘮?shù),都是當(dāng)作參數(shù)被傳遞的。而立即執(zhí)行函數(shù)它本身就是個(gè)匿名函數(shù), js代碼執(zhí)行的順序: //巳聲明的函數(shù) function test(){} //匿名函數(shù) function (){} //函數(shù)表達(dá)式 var test = function(){} //立即執(zhí)行函數(shù) (function(){})();
立即執(zhí)行函數(shù)配合閉包,在模塊化中的應(yīng)用,其中要明白幾個(gè)點(diǎn):
1、要在函數(shù)體后面加括號(hào)就能立即調(diào)用,則這個(gè)函數(shù)必須是函數(shù)表達(dá)式,不能是函數(shù)聲明; 2、立即執(zhí)行函數(shù)可以當(dāng)作是一個(gè)私有作用域,作用域內(nèi)部可以訪問外部的變量,而外部環(huán)境是不能訪問作用域內(nèi)部的變量的,因此,立即執(zhí)行函數(shù)是一個(gè)封閉的作用域,不會(huì)和外部作用域起沖突。 JQuery使用的就是這種方法,將JQuery代碼包裹在( function (window,undefined){…jquery代碼…} (window)中,在全局作用域中調(diào)用JQuery代碼時(shí),可以達(dá)到保護(hù)JQuery內(nèi)部變量的作用。 3、Module模式,是自執(zhí)行函數(shù)的高級(jí)模式,可以非常方便的在各個(gè)匿名閉包中以全局對(duì)象調(diào)用閉包函數(shù)。有興趣可以查看:http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html Module 模式為: a.創(chuàng)建一個(gè)立即調(diào)用的匿名函數(shù)表達(dá)式 b.return一個(gè)變量,其中這個(gè)變量里包含你要暴露的東西 c.返回的這個(gè)變量將賦值給window
(function () {
var i = 0; return { get: function () { return i; }, set: function (val) { i = val; }, increment: function () { return ++i; } };
} (window));
// window作為一個(gè)帶有多個(gè)屬性的全局對(duì)象,上面的代碼對(duì)于屬性的體現(xiàn)其實(shí)是方法,它可以這樣調(diào)用: window.get(); // 0 window.set(3); window.increment(); // 4 window.increment(); // 5 window.i; // undefined 因?yàn)閕不是返回對(duì)象的屬性 i; // 引用錯(cuò)誤: i 沒有定義(因?yàn)閕只存在于閉包)
/上面就是關(guān)于自調(diào)用匿名函數(shù)的解析,那么這樣的函數(shù)它是怎么被調(diào)用的呢?*/
/下面是關(guān)于全局變量的調(diào)用,也就是匿名閉包函數(shù)的調(diào)用*/
再次搬出Module模式,有興趣可以查看:http://www.cnblogs.com/TomXu/...
Module 模式,也就是匿名閉包的創(chuàng)建與調(diào)用:
a.創(chuàng)建一個(gè)立即調(diào)用的匿名函數(shù)表達(dá)式 b.return一個(gè)變量,其中這個(gè)變量里包含你要暴露的東西 c.返回的這個(gè)變量將賦值給window
window(或者是任意一個(gè)全局對(duì)象)作為一個(gè)帶有多個(gè)屬性的全局對(duì)象,也可以把window當(dāng)成一個(gè)參數(shù),以對(duì)象的方式,在其它函數(shù)中實(shí)現(xiàn)調(diào)用。用下面的例子說(shuō)明:
(function ($, YAHOO) {
// 這里,我們的代碼就可以使用全局的jQuery對(duì)象了,YAHOO也是一樣 $.aa = function(){ //code }
} (jQuery, YAHOO));
//調(diào)用 jQuery.aa();
下面是一個(gè)標(biāo)準(zhǔn)的Module模式,通過匿名函數(shù)的返回值來(lái)返回這個(gè)全局變量:
var blogModule = (function () {
var my = {}, privateName = "博客園"; function privateAddTopic(data) { // 這里是內(nèi)部處理代碼 } my.Name = privateName; my.AddTopic = function (data) { privateAddTopic(data); }; return my;
} ());
//調(diào)用 blogModule.my();
在一些大型項(xiàng)目里,將一個(gè)功能分離成多個(gè)文件是非常重要的,因?yàn)榭梢远嗳撕献饕子陂_發(fā)。再回頭看看上面的全局參數(shù)導(dǎo)入例子,我們能否把blogModule自身傳進(jìn)去呢?答案是肯定的,我們先將blogModule傳進(jìn)去,添加一個(gè)函數(shù)屬性,然后再返回就達(dá)到了我們所說(shuō)的目的:
var blogModule = (function (my) {
my.AddPhoto = function () { //添加內(nèi)部代碼 }; return my;
} (blogModule || {}));
或
(function (my){
my.AddPhoto = function () { //添加內(nèi)部代碼 }; return my;
})(blogModule || {}));
//調(diào)用 blogModule.AddPhoto();
那么,多個(gè)自執(zhí)行函數(shù)間是怎么調(diào)用的呢?
(function(owner) {
//第一個(gè)匿名閉包 owner.debug = true; //Ajax相關(guān)參數(shù)配置 owner.ajax = { timeout: 10000, type: "post", dataType: "json", };
})(window.C = {}));
如果第二個(gè)函數(shù)想調(diào)用 全局變量為C中的 對(duì)象呢?要怎么寫?
(function($, owner) {
//這里調(diào)用上面全局變量為C 中的對(duì)象呢 if(!C.debug) return false; var url = "aaa.html"; mui.ajax({ url: url, dataType: C.ajax.dataType, type: C.ajax.type, });
})(mui, window.app = {});
再舉個(gè)例子,同樣的,不同自執(zhí)行閉包函數(shù)間的調(diào)用方法:
(function($, owner) {
//獲取語(yǔ)言閉包 owner.getLanguage = function() { var language = localStorage.getItem(C.state.field.language); if(typeof language == "undefined" || language === null || language == "") { var currentLang = navigator.language; if(!currentLang) currentLang = navigator.browserLanguage; language = currentLang.toLowerCase(); language = language.replace(/-/g, "_"); if(language != "en_us" && language != "zh_cn") language = "en_us"; localStorage.setItem(C.state.field.language, language); } //在上面的解析中有說(shuō)過,Module模式,return 一個(gè)變量,這個(gè)變量就是要爆露的東西。通過這個(gè)函數(shù)的全局變量,這個(gè) language 可以在任何地方調(diào)用 //return一個(gè)變量,其中這個(gè)變量里包含你要暴露的東西 //全局調(diào)用 storage.language return language; };
})(mui, window.storage = {}));
(function($, owner) {
owner.language = {}; owner.preload = function(settings){ var defaults = { name: "i18n", language: "", path: "/", cache: true, encoding: "UTF-8", autoReplace: true, success: null, error: null, }; settings = $.extend(defaults, settings); if(settings.language === null || settings.language == "") { //全局調(diào)用 storage.language settings.language = storage.getLanguage(); } }
})(mui, window.i18n = {});
所以 匿名閉包的調(diào)用規(guī)則是這樣的,立即執(zhí)行(最后一個(gè)括號(hào)) (window),如果把window作為一個(gè)參數(shù)進(jìn)行傳遞,那么就把它以對(duì)象的方式,在其它函數(shù)中實(shí)現(xiàn)全局調(diào)用。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/96487.html
摘要:在函數(shù)內(nèi)部定義的匿名函數(shù)的作用域鏈中,不包含外部函數(shù)的活動(dòng)對(duì)象。在執(zhí)行完畢以后,其執(zhí)行環(huán)境的作用域鏈被銷毀,但是其活動(dòng)對(duì)象不會(huì)被銷毀,因?yàn)槟涿瘮?shù)的作用域鏈中仍然引用著這個(gè)活動(dòng)對(duì)象,直到匿名函數(shù)執(zhí)行完畢后,才一起被銷毀。 函數(shù)表達(dá)式和函數(shù)聲明 函數(shù)聲明:function 函數(shù)名稱 (參數(shù):可選){ 函數(shù)體 } 函數(shù)表達(dá)式:function 函數(shù)名稱(可選)(參數(shù):可選){ 函數(shù)體 }...
摘要:前言大家學(xué)的時(shí)候,經(jīng)常遇到自執(zhí)行匿名函數(shù)的代碼,今天我們主要就來(lái)想想說(shuō)一下自執(zhí)行。其實(shí),前面兩個(gè)例子里的變量,也可以換成,因?yàn)楹屯饷娴牟辉谝粋€(gè)作用于,所以不會(huì)出現(xiàn)問題,這也是匿名函數(shù)閉包的威力。 前言 大家學(xué)JavaScript的時(shí)候,經(jīng)常遇到自執(zhí)行匿名函數(shù)的代碼,今天我們主要就來(lái)想想說(shuō)一下自執(zhí)行。 在詳細(xì)了解這個(gè)之前,我們來(lái)談了解一下自執(zhí)行這個(gè)叫法,本文對(duì)這個(gè)功能的叫法也不一定完全對(duì)...
摘要:總結(jié)上面的大部分方式都可以互相組合使用的,一般來(lái)說(shuō)如果要設(shè)計(jì)系統(tǒng),可能會(huì)用到松耦合擴(kuò)展,私有狀態(tài)和子模塊這樣的方式。 簡(jiǎn)介 Module模式是JavaScript編程中一個(gè)非常通用的模式,一般情況下,大家都知道基本用法,本文嘗試著給大家更多該模式的高級(jí)使用方式。 首先我們來(lái)看看Module模式的基本特征: 模塊化,可重用 封裝了變量和function,和全局的namaspace不接觸...
摘要:第一部分執(zhí)行代碼之后,返回了一個(gè)新的匿名函數(shù),此時(shí)在全局作用域調(diào)用匿名函數(shù)它不在是的屬性或者方法,此時(shí)調(diào)用者是因此輸出是??偨Y(jié)關(guān)于中的,記住誰(shuí)調(diào)用,就指向誰(shuí)要訪問閉包的,要定義個(gè)變量緩存下來(lái)。 前言: 這是一篇關(guān)于閉包函數(shù)的總結(jié)和筆記 希望對(duì)大家有點(diǎn)幫助 寫的不好的地方,也請(qǐng)大家多多指教 一: js中的命名函數(shù),匿名函數(shù),自調(diào)用函數(shù)和回調(diào)函數(shù) 1.命名函數(shù): 函數(shù)如果有名字,就...
摘要:匿名函數(shù)是不能單獨(dú)寫的,所以就提不上立即執(zhí)行了。六立即執(zhí)行函數(shù)在閉包中的應(yīng)用立即執(zhí)行函數(shù)能配合閉包保存狀態(tài)。來(lái)看下上節(jié)內(nèi)容中閉包的例子現(xiàn)在,我們來(lái)利用立即執(zhí)行函數(shù)來(lái)簡(jiǎn)化它第一個(gè)匿名函數(shù)執(zhí)行完畢后,返回了第二個(gè)匿名函數(shù)。 前面的閉包中,提到與閉包相似的立即執(zhí)行函數(shù),感覺兩者還是比較容易弄混吧,嚴(yán)格來(lái)說(shuō)(因?yàn)橄透叱虒?duì)閉包的定義不同),立即執(zhí)行函數(shù)并不屬于閉包,它不滿足閉包的三個(gè)條件。...
閱讀 1529·2021-11-18 10:02
閱讀 1680·2021-09-04 16:40
閱讀 3180·2021-09-01 10:48
閱讀 882·2019-08-30 15:55
閱讀 1860·2019-08-30 15:55
閱讀 1379·2019-08-30 13:05
閱讀 3022·2019-08-30 12:52
閱讀 1632·2019-08-30 11:24