# Day 24：函數呼叫 (Function Invocation) 與立即函數 (Self-Invoking Functions)

Day19 的文章曾介紹傳統函數定義 (Function Definition) 的 ~~100 種~~ 4 種寫法，定義了也得有人呼叫才有用，那今天來介紹函數呼叫 (Function Invocation) 吧。

根據場合，函數有 3 種被呼叫的時機，其中立即函數 (Self-Invoking Functions) 是特別有趣的一種，會花比較多篇幅介紹。

## 函數有三種被呼叫的時機

### 1. HTML 事件觸發

JavaScript 可以和 HTML 元件 (HTML Elements) 互動，例如點擊按鈕、偵測鍵盤、瀏覽器載入完畢等。

事件 (Events) 就是發生在 HTML 元件的狀況。

> W3Schools: HTML events are "things" that happen to HTML elements.

當事件被偵測到時，JavaScript 就能呼叫指定的函數執行對應動作。

HTML 事件有很多種類，最常見的就是 `onclick`：

```javascript
<button onclick="sayHello()">Click Me</button>
<script>
function sayHello(){
    alert('Hello');
}
</script>
```

### 2. 由其他 JavaScript 程式碼主動呼叫

這應該是程式中最普遍的呼叫方式：

```javascript
sayHello();

function sayHello(){
    console.log('Hello');
}
```

### 3. 立即函數 (Self-Invoking Functions)

#### 快速複習一下函數表達式 (Function Expressions) 的概念

Day19 介紹過函數表達式 (Function Expressions) 形式的函數定義語法：

* 匿名表達式 (Function Expressions w/o Function Name)
* 具名表達式 (Function Expressions w/ Function Name)

複習一個簡單的函數表達式範例：

```javascript
var sayHello = function () {
    console.log('Hello');
};

sayHello();     // "Hello"
```

語法可以分匿名和具名，但具名沒什麼意義。

```javascript
var sayHello = function abc() {
    console.log('Hello');
};

abc();          // ReferenceError: abc is not defined
```

因為**透過 Function Expressions 定義的函數，我們實際在使用時，無法透過函數名稱 (`abc`) 取得函數物件，而是透過變數名稱 (`sayHello`) 取得函數物件**，然後執行該函數物件。

#### 函數定義用小括號包起來，一律代表 Function Expressions

這個小地方容易有概念上的模糊。

以下是一個**宣告式 (Function Declarations)** 的函數用法：

```javascript
function sayHello() {
    console.log('Hello');
};

sayHello();     // "Hello"
```

`sayHello` 是函數名稱，**宣告式的函數，我們可以直接透過函數名稱來取得函數物件，並且執行**。

**但一旦使用小括號將函數宣告式包裝起來，原本的 Function Declarations 也會被視為 Function Expressions**。

例如以下：

```javascript
(function sayHello() {
    console.log('Hello');
});

sayHello();     // ReferenceError: sayHello is not defined
```

如前面提到，透過 Function Expressions 定義的函數，無法透過函數名稱 (`sayHello`) 取得函數物件本身。而上面例子並沒有將這個函數物件儲存於任何變數，等於沒有機會去呼叫它。

所以如果使用 Function Expressions，幾乎都會宣告一個變數去儲存，並且不為函數特別具名。

#### 對函數表達式作立即性的呼叫 (Self-Invoking Expressions)

但如果 Function Expressions 是一次性的，只會使用一次，而且是馬上使用，就可以不用將函數物件另外存放到變數裡，而是加上 `()` 符號要求立刻執行：

```javascript
(function () {
    console.log('Hello');
})();
```

執行結果：

```
Hello
```

這就是為什麼本篇文章將 Self-Invoking Expressions 稱為「立即函數」，精確的名稱應該要翻「自我呼叫的函數表達式」，但立即函數這個名稱我認為在概念上更有助記憶和理解。

如同前面提到，函數表達式可以具名，語法上可以被接受。但實際上具名的函數名稱無法被呼叫，毫無意義：

```javascript
(function abc() {
    console.log('Hello');
})();

abc();
```

執行結果：

```
Hello
Uncaught ReferenceError: abc is not defined
```

所以**立即函數不需要具名**。

#### 不能對函數宣告 (Function Declarations) 作立即呼叫

> W3Schools: You cannot self-invoke a function declaration.

例如以下語法是不成立的：

```javascript
function sayHello() {
    console.log('Hello');
}();
```

一定要先包裝成一個 Function Expression，才能進行立即呼叫。

## 總結

**函數有三種被呼叫的時機：** 1. HTML 事件觸發 2. 由其他 JavaScript 程式碼主動呼叫 3. 立即函數

**立即函數使用重點：**

* 函數定義用小括號 `(` 和 `)` 包起來，一律代表 Function Expressions (即使原本是 Function Declarations)。
* 在 Function Expressions 後面加上 `()`，就能作立即性的呼叫。
* 立即函數不需要具名。
* 不能對函數宣告 (Function Declarations) 作立即呼叫。

## References

* [W3Schools - JavaScript Functions](https://www.w3schools.com/js/js_functions.asp)
* [Javascript 開發學習心得 - 函數的多種寫法與應用限制](https://sweeteason.pixnet.net/blog/post/40371736)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://something-about-js-book.onejar99.com/day24.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
