---
# System prepended metadata

title: Function
tags: [javascript]

---

# Function
###### tags: `javascript`

Every JavaScript function is actually a `Function` object. This can be seen with the code `(function(){}).constructor === Function` which returns `true`.

> 以下測試皆在Google Chrome進行測試。
> 我沒有要在這裡討論Hoisting和`this`的問題，so麻煩，`this`已經寫完了，hoisting有空再縮。
> 這邊的上下排序，是按照比較越常看到而且一般看到會很有問題的先寫，而不是一班學習的順序。所以那個宣告甚麼的我才會放在最後面。

## Function可以怎麼用

### 使用`apply`和`call`來進行呼叫
* 跟一般呼叫沒有什麼兩樣，只是這樣可以指定執行時的`this`指向。
* 呼叫`call`或`apply`，第一個參數填上要指定的`this`的指向，後面參數依序填入。
* 去看`this`的那一篇的Explicit binding。
* `call`和`apply`有空會再寫一篇他們的差別。

```javascript=
function squareArea ( width, height ) {

    console.log ( width );
    console.log ( height );
    
    return width * height;
}

console.log ( squareArea.call ( null, 2, 3 ) );    // output: 2
                                                   //         3
                                                   //         6
```

### 把它`new`出來
* 假設我們對一個function做`new`的動作，就相當說把這個function當作一個class來看待，那既然是一個class那就可以對它`new`出一個instance，此時這個function就會是一個建構式的角色。
* 如果這個建構式沒有回傳東西的話，那他會回傳這個新建出來的物件。
* 詳細的情形，我是打算再寫一篇關於JS的OO啦，看有沒有空。
```javascript=
function Rectangle ( width, height ) {
    
    this.width = width;
    this.height = height;
    
    this.area = function ( ) {
        return this.width * this.height;
    }
}

let square = new Rectangle ( 5, 5 );
console.log ( square.area () );    // output: 25
```

> 於是乎，`square`會是一個`Rectangle`的物件，它有兩個property，分別是`width`和`height`，還有一個method叫做`area`。

### 一般呼叫
就是加上小括號（`()`），它就會動了，它就會執行了，so easy。
```javascript=
function square ( number ) {
    return number * number;
}

console.log ( square ( 2 ) );    // output: 4
```

## Function到底可以做到那些事
* 如同，最上面所說，所有的function都是物件，一種型別為`Function`的物件。所以所有能對Object做的事情，都能對function做。
* 就把funciton當作一個_**_可執行的object就對了_**_。

### 給他一些屬性
既然是個Object它就可以有一些屬性吧。

```javascript=
function square ( number ) {
    return number * number;
}

square.digit = "cm";

console.log ( square ( 2 ) ); // output: 4
console.log ( square )        // output: ƒ square ( number ) { return number * number; }
console.log ( square.digit ); // output: "cm"
```

> 可以注意到，即使加上屬性也完全不會影響function的運作。

### 任何地方都可以宣告
對，這很重要，因為你可以在*function裡面再宣告function*。
```javascript=
function outerFunction ( callback ) {
    
    function innerFunction ( ) {
        console.log ( "inner function" );
    }
    
    console.log ( callback );        // output: ƒ ( ) { console.log ( "callback function" ); }
    callback ( );                    // output: "callback function"
    
    console.log ( innerFunction );   // output: ƒ innerFunction ( ) { console.log ( "innerFunction" ); }
    innerFunction ( );               // output: "inner function"
}

outerFunction ( function ( ) {
    
    console.log ( "callback function" );
    
} );
```

> 對，就是把它當一個物件用，所以可以在傳參數的時候，直接傳過去用。
> function要使用的時候，就是再加小括號`()`，就會執行了。


### 把function指派給變數
既然function是個物件，那就是個值（value），那應該可以assign給某些變數吧。

```javascript=
function square ( number ) {
    return number * number;    
}

let func = square;
let obj = { func: square };

console.log ( square );            // output: ƒ square ( number ) { return number * number; }
console.log ( func );              // output: ƒ square ( number ) { return number * number; }
console.log ( obj );               // output: { func: ƒ square ( number ) }
console.log ( obj.func );          // output: ƒ square ( number ) { return number * number; }

console.log ( square ( 2 ) );      // output: 4
console.log ( func ( 2 ) );        // output: 4
console.log ( obj.func ( 2 ) );    // output: 4
```

> 可以看到不僅可以assign給變數，使用方法跟結果完全不變

## Function要如何宣告

宣告方式簡單來縮，有5種，但是有2個根本就沒有在用。

### 宣告式（Function Declarations）
* 最標準最普通最簡單的寫法

```javascript=
function square ( number ) {
    return number * number;
}

console.log ( square ( 2 ) );  // output: 4
console.log ( square );        // output: ƒ square ( number ) { return number * number; }
```

### 匿名表達式（Function Expressions w/o Function Name）
* 簡單來縮就是宣告一個變數，然後它的值是一個function，把function當object看就對了，所以它可以存在一個變數裡面（往下看function可以做哪些事）。
* 這個function沒有名稱喔，這就是一個匿名函式（anonymous function）。
* 建議這個變數宣告使用`const`，畢竟函數的定義不該被更改。

```javascript=
const square = function ( number ) {
    return number * number;
}

console.log ( square ( 2 ) );    // output: 4
console.log ( square );          // output: ƒ ( number ) { return number * number; }
```

> 可以注意到在後面`square`的輸出中的function是沒有名字的。

### 具名表達式（Function Expressions w/ Function Name）
* 跟上面那個一模一樣，只是function定義時多了名字，這邊的function是有名字的，只是那個名字被有啥鳥用，畢竟拿不到那個名字來做事。
* 沒有人在用這個啦！

```javascript=
const square = function squareRealName ( number ) {
    return number * number;
}

console.log ( square ( 2 )         // output: 4
console.log ( square );            // output: ƒ squareRealName ( number ) { return number * number; }
console.log ( squareRealName );    // ReferenceError: squareRealName is not defined
```

### 建構子式（Function Constructor）
* 所以我前面有縮，把function當object來看待，所以，它也有它的Constructor。
* 所有JavaScipt的funciton都是`Function`型態（看看最上面一句話），所以你可以透過`new Function ( )`，把它`new`出來。
* 建立出來的function基本上就跟前面那個（具名表達式）的結果一樣，這個function的名字叫做anonymous，一樣沒啥鳥用。
* 沒有人在用這個啦！

```javascript=
const square = Function ( "number", "return number * number" );

console.log ( square ( 2 ) );    // ooutput: 4
console.log ( square );          // output: ƒ anonymous(number) {return number * number}
```

> 可以看到那個被new出來的function是有名字的就叫做`anonymous`。

### 箭頭函式（Arrow Function）
去看ES6新功能的那一篇啦


## 參考資料
* 函數定義 (Function Definition) 的 100 種寫法：https://ithelp.ithome.com.tw/articles/10207740
* Function：https://ithelp.ithome.com.tw/articles/10194538
* Function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function