iT邦幫忙

4

[筆記][JavaScript]關於即刻執行函式(immediately invo....IIFE)的用法

嗨啊啊啊,首先我要先道歉一下,感覺我很多觀念都還沒打穩,所以打文章的時候並沒有講解的很清楚,只是想說如果試著去理解,並且打出來和大家分享應該會得到更厲害的大大的建議,當然也是真的有啦!但總覺得如果是這樣有點不太好意思,雖然把他歸類成筆記,但是既然文章出來了,也是一種技術分享,就覺得應該要更認真的去做好這件事情才行。

另外我也在板上另一個大大fysh711426的文章[Google Code Jam] 2018 資格賽中答應說也要試著來解一下問題,關於這個我原本想說用JavaScript來處理掉,但是現在還沒有去處理到這部分,哦怎麼覺得從客戶那欠東西欠到這裡了/images/emoticon/emoticon16.gif,不過相信我,我一定會找時間把它處理掉的,如果板上其他大大有興趣也可以去看一下問題在這裡!啊啊啊現在先不要點進去,這篇文章的主題都還沒開始,那題外話就不再多說,以下開始!

關於即刻執行函數(immediately invoked function expression),這個不管是中文或是英文都很長,所以大家都簡稱IIFE,他的意思就如同字面,就是撰寫完函式內容後,直接呼叫執行該函數,以下例子:

//一個一般的函式會是以下這樣
var funcA = function(){
    console.log('hello!');
};
//去執行他
funcA();  //會在console中印出'hello!'

//而IIFE看起來會是以下這樣
(function funcB(){ //IIFE的開頭
    console.log('hello!') //函式內執行的內容
}()); //IIFE的結尾
//不需要特別去執行就會直接在console中印出hello!

funcB();  //但是當我們去做呼叫時會出現「funcB is not defined」的錯誤,因為在IIFE開頭的括號是代表這段程式碼是作為一個述句執行裡面的運算式,並不是以function去宣告函式,所以他也不會被存在全域變數中,也就不可能呼叫的到了。

接下來繼續改寫IIFE的內容,IIFE接在函式後右大括號的兩個小括號會讓函式即刻被執行,也就是說他是靠那個小括號去呼叫的,所以我們可以利用他去加入參數:

//IIFE可以是匿名函式(就是不幫函式取名字),因為他馬上就會執行了,之後也不需要再呼叫他,所以有沒有名字都無所謂。
(function(str){   //我們在這裡加入str用來裝執行時傳入的參數。
    console.log(str);
}('hello'));   //我們把字串'hello'傳入IIFE中
//不需要執行便會直接在console中印出hello

再來我們看一下IIFE的奇行種/images/emoticon/emoticon37.gif,上面第一個例子的最後有提到說,開頭的括號是作為一個述句宣告,為了能讓裡面的程式碼變成運算式執行,所以說其實只要能夠讓該匿名函式變成運算式都能夠當成IIFE來使用!例如以下:

//function和上面例子一樣,不同的是把原本包著他的括號拿掉,並在前面放一個!運算子
!function(str){   
    console.log(str);
}('hello'); 
//登愣!會發現他還是會在console中印出hello,但是他會回傳個結果true,因為!運算子會回傳boolean的值,而該函式沒有return東西也就是undefined,但是!是Not運算子,所以會把結果從undefined的false轉成ture回傳,好,這是有點長的題外話,那我們繼續看下去。

//如果他本身就是在運算子的環境中,甚至不需要再把他變成運算子,例如:
var funcA = 
    function(str){   
        console.log(str);
    }('hello'); 
//一樣會直接在console中印出hello!

好的,那我們講了那麼多IIFE,但是他到底可以用在什麼地方呢?大家應該都知道JavaScript的變數範圍有分成全域和區域,IIFE就是為了讓全域變數的環境不被全域變數汙染,和在區域中,建立一個新的環境,避免在同個區域內共用同個變數。

讓我們看看以下在全域環境使用的例子:

//先建立幾個簡單的函式
function writeStr(str){
    console.log(str);
};
function setValue(){
    return 'A'
};
//在全域中使用
var strA = setValue();  //設定strA的值
writeStr(strA);  //把strA的值交給函式writeStr印出到console

strA; //會回傳'A'因為他已經被存在window,也就是全域環境中了

//雖然以上這麼做是沒問題的,但是全域環境會增加一個strA,這對於依賴全域環境做執行的JavaScript容易出現一些問題,所以我們應該要避免汙染到全域變數,如下:
//建立IIFE
(function(){
    var strB = setValue();   //在IIFE中的匿名函式中宣告該變數,他的範圍就只會在這個IIFE中,不會汙染到全域環境。
    writeStr(strB);  //一樣把strA丟到函式writeStr印到console上
}());

strB; //會出現strB is not defined的錯誤,全域變數沒被汙染

最後是在區域中使用的例子:

//建立一個一般的函式,並觀察temp在各個地方的變化
function funcA(str){
    var temp = '';
    console.log('(1):' + temp);
    if(str !== ''){
        var temp = str;
        console.log('(2):' + temp);
    }
    console.log('(3):' + temp);
};

funcA('hello');  
//執行後會在console上印出:
//(1):''
//(2):hello
//(3):hello
//會發現在if內宣告的同名變數temp會在if中設定新的值後,會連整個函式funcA原本的temp值都改變了。

//接著在函式內使用IIFE,再觀察temp的變化
function funcB(str){
    var temp = '';
    console.log('(1):' + temp);
    if(str !== ''){
        (function(){
        var temp = str;
        console.log('(2):' + temp);}());
    }
    console.log('(3):' + temp);
};

funcB('hello');
//執行後會在console上印出:
//(1):''
//(2):hello
//(3):''
//可以看到temp這個變數在IIFE中被改變的內容並不會遺留到IIFE外的任何地方,這樣就可以避免在同個環境執行時,共用同個變數名稱會影響到原本的內容。

以上是對IIFE的一些說明和應用,如果有說明錯誤或不明白的地方,麻煩再留言告知我,我會盡速改正!!謝謝大家!!


1 則留言

0
fysh711426
iT邦新手 2 級 ‧ 2018-04-15 12:51:31

我相信你,等你的 JavaScript 解答出爐 /images/emoticon/emoticon01.gif

我要留言

立即登入留言