# IIFEs 立即函式
>**Immediately Invoked Function Expressions 即刻調用的函式運算式**
>指的就是透過 function expression(函式運算式) 的方式來建立函式,並且立即執行它
<br>
#### Question
Explain why the following doesn't work as an IIFE: `function foo(){ }();`. What needs to be changed to properly make it an IIFE?
<br>
## 前言
### 表達式(Expressions)和 陳述句(Statements)的差異
#### 表達式(Expressions)
Expressions 指的是輸入後能夠直接回傳值的一串程式(**a unit of code that results in a value**)

<br>
#### 陳述句(Statements)
```+
if (a === 3) {
console.log('Hello');
}
```
在這段程式中 `a === 3` 是一個表達式(expression),因為它可以直接回傳值(即,`true` 或 `false`);而 if 這個指令,則是一個 statement
<br>
****
## Function Statement(Declaration) 函式述句(宣告) v.s. Function Expression 函式運算式
> **Functions are objects**
### Function Statements
```+
function greet() {
console.log('Hi');
}
```

<br>
### Function Expressions
因為在 JavaScript 中 Function 就是物件的一種,所以我們可以把它存在一個變數中:
```+
const sayHello = function() {
console.log('Hello');
};
```
這裡的 `function(){ ... }` 這段就是 Function Expression,現在我們則把這個函式表達式的值存在 `sayHello` 這個變數內。

<br>
***和 Function Statements 不同的地方 ( 補充 )***
使用 Function expression 的話不能在定義前呼叫它
```+
sayHello();
const sayHello = function() {
console.log('Hello');
};
```

<br>
****
## IIFE 立即函式
#### Function Statement
當 syntax parser 在一行程式碼的最前面看到 `function` 時,就會認定他是一個 function statement
```+
function foo(){
console.log("foo");
}
```
>**所以當我們寫出`function foo(){}()` 時,syntax parser 認為在一個 function statement 後看到不應該出現的`()` 因此顯示錯誤 **

<br/>
#### 轉為 Function Expression
當我們用 `()` 把一個 function statement 包裹起來,函式不會被當成一個標準的 function statement (declaration),而是**當作一個函式運算式 function expression**
*註:`()` 在這裡會被當成一個 expression 中 grouping 的 operator 運算子,像是 `(2+3)*4` 一樣 *
```+
(function foo(){
console.log("foo");
})
```

<br/>
#### Immediately Invoked Function Expressions
在我們建立函式的同時,加上一個執行的指令,也就是括號 `()` 這段函式就會立即被執行了
```+
(function foo(){
console.log("foo");
})()
```

<br />
#### IIFEs 的另一種寫法
兩種都可以,是個人選擇,不過 prettier 等等會校正成另一種
```+
(function (name) {
console.log("Hello " + name);
}())
```
<br>
##### 另一種例子 (較少見)
```+
const greetMyself = function(name) {
return('Welcome ' + name);
}("WYT");
console.log(greetingMySelf);
//Welcome WYT
```
<br>
***
#### Anonymous IIFE 匿名立即函式
###### 錯誤範例
syntax parser 首先看到 `function` keyword,認定他是一個 function statement,syntax parser 找不到這個 function 的名字,於是它無法正確理解這段程式碼,而拋出錯誤:
```+
function (name) {
console.log("Hello " + name);
}
```

<br />
##### 用 `()` 包裹匿名函式讓它變成 function expression
syntax parser 首先看到 `()` keyword,認定他是一個 expression,因為
```+
(function (name) {
console.log("Hello " + name);
})
```

<br />
##### 用另一對`()` 傳入argument,執行 function
```+
(function (name) {
console.log("Hello " + name);
})("I am anonymous IIFE")
```

<br>
****
### 用 IIFE 讓全域環境不受污染
> 不少JS框架、套件的開頭與結尾被`()`包住,程式碼被立即函式包著,其目的是怕污染到使用者(開發者)的全域環境。
在ES6出來前,為了避免設定太多的全域變數,開發者往往會將變數設定在函式中,使其成為區域變數,尤其是設定在IIFE中,確保不會汙染到全域環境的變數。
```+
const seafood = '波士頓龍蝦';
(function(name){
const seafood = '北海道帝王蟹';
console.log(name + '好想吃' + seafood);
}('Simon'));
// Simon好想吃北海道帝王蟹
```
因為執行環境的不同,'北海道帝王蟹'只存在IIFE裡,不會影響到外部環境的變數。
也就是說,我們可以將程式碼包在被()包住的IIFE裡,當IIFE和全域環境有宣告相同變數名稱時,IIFE不會蓋掉全域的變數。
****
### 總結 IIFE 用途
使用立即函式的好處,除了可以立即執行程式碼,省略多餘的呼叫,還可以用來避免汙染全域執行環境的東西,減少開發時因相同命名相衝的bug。
****
### 參考資料
- Udemy - JavaScript: Understanding the Weird Part (lecture 34, 35, 44 )
- 你你所不知道的JS|範疇與Closures,this 與物件原型 p.34~p.38
- [[筆記] 進一步談JavaScript中函式的建立─function statements and function expressions](https://pjchender.blogspot.com/2016/03/javascriptfunction-statements-and.html)
- [[筆記] 談談JavaScript中的IIFEs(Immediately Invoked Functions Expressions)](https://pjchender.blogspot.com/2016/05/javascriptiifesimmediately-invoked.html)
- [Day20 立即呼叫的函式表示式(IIFE)](https://ithelp.ithome.com.tw/articles/10193313)