2016年5月11日

[筆記] 談談JavaScript中的IIFEs(Immediately Invoked Functions Expressions)

為了要進一步了解不同的 framework 程式撰寫的意思,我們需要進一步學習和了解 IIFEs 這個概念。
IIFEs(Immediately Invoked Functions Expressions) 其實可以就字面上直接來理解,Immediately 就是立即的意思,invoked 則是執行某個函式時,「執行」的意思,function expression 是一種用來建立 function 的方法,總括來說,就是用 function expression 的方式建立函式後並立即執行它
下面我們將做更進一步的介紹和說明。

Function Statement 和 Function Expression

在之前的文章中,我們有提到,建立 function 的方法通常有 function statementfunction expression 這兩種方式,如果還不太清楚的話,可以參考這篇[筆記] 進一步談JavaScript中函式的建立─function statements and function expressions,這裡就不另外贅述。
// function statement
function sayHello(name) {
  console.log('Hello ' + name);
}
sayHello('PJCHEN');

// function expression
var sayWelcome = function(name) {
  console.log('Welcome, ' + name);
}
sayWelcome('PJCHEN');

Immediately Invoked Functions Expressions (IIFEs)

那麼什麼是 IIFEs 呢?如同文章一開始所敘述的,IIFEs 指的就是透過 function expression 的方式來建立函式,並且立即執行它。我們要怎麼作呢?
首先我們可以用 console.log 的方式,先來看一下,我們剛剛建立的 sayWelcome 呼叫出來會長什麼樣子。
// function expression
var sayWelcome = function(name) {
  console.log('Welcome, ' + name);
}

console.log(sayWelcome);
結果會發現,把 sayWelcome 呼叫出來後,它會直接回傳整個函式的程式碼內容,這是尚未"執行(Invoked)"程式碼前的結果。
imgur
如果是 IIFEs 就在這段程式碼的最後,加上一個執行的指令,也就是括號 ( )
// Immediately Invoked Functions Expressions (IIFEs)
var sayWelcomeIIFEs = function(name) {
  console.log('Welcome ' + name);
}();
在我們建立函式的同時,這段函式就會立即被執行了!
這裡面同樣可以帶入參數:
// Immediately Invoked Functions Expressions (IIFEs)
var sayWelcomeIIFEs = function(name) {
  console.log('Welcome ' + name);
}('PJCHEN');
imgur
讓我在把 function 裡面的 console.log 改成 return,在看一次。
原本 function expression 的程式碼如下:
// Function Expression
var sayWelcome = function(name) {
  return('Welcome ' + name);
};
console.log(sayWelcome);
這時候,如果使用 console.logsayWelcomeIIFEs 這個變數顯示出來看的話,會得到如下的結果,可以看到它還是一個函式:
如果把它改成 IIFEs 的話:
// Immediately Invoked Functions Expressions (IIFEs)
var sayWelcomeIIFEs = function(name) {
  return('Welcome ' + name);
}('PJCHEN');
console.log(sayWelcomeIIFEs);
就會直接得到 "Welcome PJCHEN" 的結果:
要注意的是,在利用 IIFE 的寫法後,原本的變數 sayWelcomeIIFEs 已經變成函式執行後回傳的「字串」,它已經是字串了,所以我們沒辦法在去執行它!
如果我們硬要在後面使用 () 執行它:
// Immediately Invoked Functions Expressions (IIFEs)
var sayWelcomeIIFEs = function(name) {
  return('Welcome ' + name);
}('PJCHEN');
console.log(sayWelcomeIIFEs());
這時候因為 sayWelcomeIIFEs 已經是字串了,所以如果我們在 sayWelcomeIIFEs 後面又加上 ( ) 去執行它的話,會出現錯誤!console 視窗會回傳這不是一個函式(所以沒辦法執行它):

更深入的應用 IIFEs

記得我們在 [筆記] 進一步談 JavaScript 中函式的建立─ function statements and function expressions 這篇中有提到 expression 的概念,Expressions 指的是輸入後能夠直接回傳值的一串程式(a unit of code that results in a value),我們一般可能會把它存成一個變數,但是它不一定要被存成一個變數。
一般的 expression 像是我可以直接在程式中輸入,數值、字串、甚至是物件,這時候去執行程式的時候,程式可以正確執行,而 console 視窗並不會有任何內容:
// Expression
3;

'PJCHENder';

{
  name: 'PJCHEN'
}
如果我希望我們的 function 也可以用這種方式來執行,而不用去把它建立在任何變數的話,我們可以怎麼做呢?
首先,我們可能會想這麼做:
// 不可行的做法
function(name) {
  return('Welcome, ' + name);
}
但是這麼做是不可行的,因為 JavaScript 引擎在解析程式碼的時候,它會認為你現在要輸入 function statement,因為你用 function 做為開頭,可是你卻沒有給該 function 的名稱,於是它無法正確理解這段程式碼便拋出錯誤
所以,這時候我們要做的是告訴 JavaScript 引擎說,這一整個並不是 function statement。要達到這樣的目的,我們要讓引擎在解析程式的時候,不是以讀到 function 做為開頭。
為了要達到這樣的目的,我們最常使用的做法就是用括號 ()function(){ ...} 包起來,像是這樣:
(function(name) {
  return('Welcome, ' + name);
});
因為我們只會在括弧內放入 expression,例如 (3+2),而不會放 statement 在括弧內,所以JavaScript 就會以 expression 的方式來讀取這段函式
在這種情況下,這個 function 會被建立,但是不會被存在任何變數當中,也不會被執行。
結合剛剛上面 IIFEs 的概念,我們可以在建立這個函式的同時,將這個函式加以執行,我們同樣只需要在最後加上括號 () 就可以了:
(function(name) {
  return('Welcome, ' + name);
})('PJCHEN');
這樣 IIFEs 的型式,會在許多的 JavaScript 框架中都看得到,透過這樣的方式,我們可以「直接執行某個函式(executing code on the fly)」,還有很重要的一點是,在 IIFEs 內所定義的變數並不會跑出去這個函式之外而干擾到程式其他的部分,這個部分我們會在下一個單元 [筆記] 為什麼我們要用IIFEs(Immediately Invoked Functions Expressions) 再來做更多的說明。
附帶一提的是,如果我們想要把物件也直接用 expression 來表示的話,同樣也可以用 ( ) 來把我們的物件包起來就可以了:
({
  name: 'PJCHEN',
  interest: 'Website Developer'
})

程式範例

// Function Statement
function sayHello(name) {
  console.log('Hello ' + name);
}
sayHello('PJCHEN');

// Function Expression;
var sayWelcome = function(name) {
  console.log('Welcome, ' + name);
};
sayWelcome('PJCHEN');
console.log(sayWelcome);

// Immediately Invoked Functions Expressions (IIFEs)
var sayWelcomeIIFEs = (function(name) {
  return 'Welcome, ' + name;
})('PJCHEN');

// Throw Error HERE!!
console.log(sayWelcomeIIFEs());

//Expression
(function(name) {
  console.log('Welcome, ' + name);
})('PJ');

({
  name: 'PJCHEN',
  interest: 'website engineer'
});

0 意見:

張貼留言