詳解javascript立即執(zhí)行函數(shù)表達(dá)式IIFE
一、IIFE解釋
全拼Imdiately Invoked Function Expression,立即執(zhí)行的函數(shù)表達(dá)式。
像如下的代碼所示,就是一個匿名立即執(zhí)行函數(shù):
(function(window, undefined){
// 代碼...
})(window);
二、括號的意義
2.1 包住function(){}的括號的意義
這個括號的目的,是為了把function(){}轉(zhuǎn)化為表達(dá)式。像一些庫的源碼,喜歡用如下方式代替:
~function(){
// 代碼...
}();
或者這種方式:
+function(){
// 代碼...
}();
其實(shí),作用都一樣,都是把function(){}轉(zhuǎn)化成一個可執(zhí)行的表達(dá)式,方便執(zhí)行。
如果去掉該括號,則會報(bào)錯。因?yàn)閱渭兊膄unction(){}不是可執(zhí)行的表達(dá)式,會直接報(bào)錯。如下圖:

2.1 第二個括號的意義
理解了第一個括號的意義,第二個括號就很簡單了,就是執(zhí)行表達(dá)式了。
三、參數(shù)的意義
以這段代碼為例子,講解參數(shù)
var wall = {};
(function(window, WALL, undefined){
})(window, wall);
參數(shù)分為形參和實(shí)參。
function(window, WALL, undefined)三個參數(shù)為形參,第二個括號(window, wall)的兩個參數(shù)為實(shí)參。
也即可以理解為 window == window,wall == WALL。
2.1 普通形參
普通形參是指由window和wall這樣的實(shí)際變量傳入指定,可以為任何類型的變量。一個形參就對應(yīng)一個實(shí)參
2.2 特殊形參undefined
為什么形參要多寫一個undefined,這是一個很有趣的話題。
可以知道這個示例,實(shí)參只有兩個,而形參有三個。所以在函數(shù)執(zhí)行的時(shí)候,形參undefined會默認(rèn)賦值為undefined。
形參undefined的作用如下:
2.2.1 防止特殊值undefined被惡意代碼篡改。
IE6等低版本瀏覽器,undefined是支持被修改的。而這個特殊值被修改后,像以下這種判斷就失效了。
if(wall == undefined){
// 代碼...
}
所以,這里多加一個形參的目的就是為了防止這種情況發(fā)生。只要在這個IIFE作用域內(nèi),undefined就能夠正常獲取到。
2.2.2 壓縮代碼可以壓縮undefined
因?yàn)閡ndefined作為形參,像YUI compressor這種類型的代碼壓縮工具,可以將其相關(guān)的值進(jìn)行壓縮,減小文件的體積。
四、寫法解析
4.1 普通寫法
var wall = {}; // 聲明定義一個命名空間wall
// 定義方法
(function(window, WALL, undefined){
// 給wall命名空間綁定方法say
WALL.say = function(){
console.log('hello');
};
})(window, wall);
(function(window, WALL, undefined){
// 給wall命名空間綁定方法 whoIam
WALL.whoIam = function(){
console.log('wall');
};
})(window, wall);
// 調(diào)用
wall.say();
wall.whoIam();
先定義一個命名空間,然后再給這個命名空間加?xùn)|西。這是最普遍的寫法,也是最好理解的。
不足的地方就是必須先聲明一個命名空間,然后才能執(zhí)行相關(guān)的綁定代碼。存在順序加載的問題。
4.2 放大模式
var wall = (function(window, WALL, undefined){
if(typeof WALL == 'undefined'){
WALL = {};
}
// 給wall命名空間綁定方法say
WALL.say = function(){
console.log('hello');
}
return WALL; // 返回引用
})(window, wall);
var wall = (function(window, WALL, undefined){
if(typeof WALL == 'undefined'){
WALL = {};
}
// 給wall命名空間綁定方法 whoIam
WALL.whoIam = function(){
console.log('wall');
}
return WALL; // 返回引用
})(window, wall);
// 調(diào)用
wall.say();
wall.whoIam();
放大模式的好處就是,可以不用考慮代碼加載的先后順序。
因?yàn)閖s允許wall變量進(jìn)行重復(fù)var聲明,所以這段代碼是可以執(zhí)行的。
我可以把IIFE函數(shù)拆分成多個文件進(jìn)行加載,而不會出現(xiàn)普通寫法需要注意的問題。
需要注意的點(diǎn):
1.IIFE的頭部,都要先進(jìn)行檢查命名空間是否已經(jīng)實(shí)例化,如果還沒實(shí)例化,則進(jìn)行實(shí)例化。
2.IIFE的尾部,都要return命名空間的引用,使后續(xù)代碼能夠得到最新的wall命名空間內(nèi)容。
4.3 寬放大模式
(function(window, WALL, undefined){
// 給wall命名空間綁定方法say
WALL.say = function(){
console.log('hello');
}
})(window, window.wall || (window.wall = {}));
(function(window, WALL, undefined){
// 給wall命名空間綁定方法 whoIam
WALL.whoIam = function(){
console.log('wall');
}
})(window, window.wall || (window.wall = {}));
// 調(diào)用
wall.say();
wall.whoIam();
寬放大模式的重點(diǎn)注意的地方:就是在實(shí)參部分的window.wall || (window.wall = {})。
用||運(yùn)算符進(jìn)行取巧。
如果window.wall是已經(jīng)實(shí)例化的,非not defined。則直接返回window.wall的引用,賦值給形參WALL。不會執(zhí)行||運(yùn)算符后面的內(nèi)容。
如果window.wall還未實(shí)例化,則進(jìn)行實(shí)例化。這里要注意的點(diǎn)是實(shí)例化是一個賦值操作,需要用括號包起來,變成表達(dá)式去執(zhí)行,才不會報(bào)錯。
表達(dá)式(window.wall = {})執(zhí)行完畢后,會返回新對象window.wall的引用。
寬放大模式的好處:是可以切割成多個文件進(jìn)行加載,而不必考慮文件加載的先后順序,不存在強(qiáng)耦合關(guān)系。
當(dāng)然,如果IIFE里面的方法互相引用,還是存在加載依賴的問題。這個問題可以用加載器Require.js等工具解決,這里就不討論了。
五、分文件加載IIFE要注意的點(diǎn)
;(function(window, WALL, undefined){
// 給wall命名空間綁定方法say
WALL.say = function(){
console.log('hello');
}
})(window, window.wall || (window.wall = {}));
眼尖的已經(jīng)看出區(qū)別了,就是文件開始的地方,先寫上分號;。
這樣,多個文件合并的時(shí)候,才不會出現(xiàn)收尾相接,代碼出現(xiàn)錯亂的問題。比如下面這種情況:
// a.js 文件
wall.log()
// b.js 文件
(function(window, WALL, undefined){
// 給wall命名空間綁定方法say
WALL.say = function(){
console.log('hello');
}
})(window, window.wall || (window.wall = {}));
由于a.js文件的wall.log()少寫了分號,跟b.js文件合并后,js就會認(rèn)為‘wall.log()(...)'是需要這么執(zhí)行的,結(jié)果代碼就報(bào)錯了。
覺得不錯的,可以關(guān)注模塊化這個系列的文章,容我后續(xù)碼字,敬請期待!
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
js中document.getElementById(id)的具體用法
javascript charAt() arr[i]數(shù)組實(shí)例代碼
JavaScript變速動畫函數(shù)封裝添加任意多個屬性
js實(shí)現(xiàn)圖片在未加載完成前顯示加載中字樣
element必填校驗(yàn)輸入空格問題修改正則表達(dá)式、請求攔截器實(shí)現(xiàn)所有輸入框去除首尾空格(推薦)
javascript伸縮型菜單實(shí)現(xiàn)代碼

