---
# System prepended metadata

title: '`call`、`apply`、`bind`'
tags: [javascript]

---

# `call`、`apply`、`bind`
###### tags: `javascript`
這三個method是`Function`物件最重要的三個method。
> 如果你看不懂上面那句話在銃三毀，請先去看funciton那一篇。

他們最大的共通點就是改變`this`的指向。`call`和`apply`都是拿來呼叫一個function，而`bind`的則是拿來包裝一個function。

## `call` [![MDN web docs](https://developer.mozilla.org/static/img/favicon32.7f3da72dcea1.png)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call)、`apply` [![MDN web docs](https://developer.mozilla.org/static/img/favicon32.7f3da72dcea1.png)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)

* `call`和`apply`都是去呼叫一個function。只是會指定執行的時候的`this`的指向。
    > 可以去看看`this`的那一篇的Explicit Binding。

* 兩者的差別在於參數的傳遞方法。
    * `call`的使用：
        * syntax：`fun.call(thisArg[, arg1[, arg2[, ...]]])`。
        * 簡單來縮就是，第一個參數傳`this`的指向，後面的參數會依序帶入傳給function。
    * `apply`的使用：
        * syntax：`fun.apply(thisArg, [argsArray])`。
        * 簡單來縮就是，他只有兩個參數，第一個參數一樣傳`this`的指向，第二個參數則是一個陣列（或是array-liked object，這不是很重要），這個陣列就是要去call function的時候的參數，他們會從陣列中依序帶入。

* Example 1: `call`
    ```javascript=
    function area ( width, height ) {

        console.log ( this.type );
        return width * height;

    }

    let square = {
        type: "square"
    };

    let rectangle = {
        type: "rectangle"
    };

    const squareArea = area.call ( square, 2, 2 );    // output: "square"
    const rectArea = area.call ( rectangle, 2, 3 );   // output: "rectangle"

    console.log ( squareArea );    // output: 4
    console.log ( rectArea );      // output: 6
    ```

* Example 2: `apply`
    ```javascript=
    function area ( width, height ) {

        console.log ( this.type );
        return width * height;

    }

    let square = {
        type: "square"
    };

    let rectangle = {
        type: "rectangle"
    };

    const squareArea = area.apply ( square, [2, 2] );    // output: "square"
    const rectArea = area.apply ( rectangle, [2, 3] );   // output: "rectangle"

    console.log ( squareArea );    // output: 4
    console.log ( rectArea );      // output: 6
    ```

## `bind` [![MDN web docs](https://developer.mozilla.org/static/img/favicon32.7f3da72dcea1.png)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)
* 如同最上面所說，`bind`是拿來包裝一個function，在包裝的過程中，順便指定了這個function在執行的時候的`this`指向。
* 所以`bind`並不會執行這個function，他只會回傳一個function。而這個function執行時的`this`指向已經確定了。
* Example 1: 
    ```javascript=
    function area ( width, height ) {

        console.log ( this.type );
        return width * height;

    }

    let square = {
        type: "square"
    };


    let func = area;
    let bindFunc = area.bind ( square );

    let generalResult = func ( 4, 5 );    // output: undefined, why?
    let bindResult = bindFunc ( 4, 5 );   // output: "square"

    console.log ( generalResult );        // output: 20
    console.log ( bindResult );           // output: 20
    ```
    
    > 我故意先把原本的function指定給一個變數再去做呼叫。
    > 會發現執行結果都一樣。`area`拿到的`width`和`height`都一樣。
    > 差別在於執行時的`this`不一樣。如果你不知道為甚麼第一個輸出是`undefined`的話，可以去看看`this`那一篇的Default Binding。

    ***
* 我還沒縮完，來看看`bind`的syntax吧：`function.bind(thisArg[, arg1[, arg2[, ...]]])`。
* 注意到了吧，在呼叫`bind`的時候，除了`this`的指向以外，還是可以傳一些其他的東西進去的。
* 簡單來縮就是，在包裝function的同時，我們也指定了前面幾個參數的值。
* 如果這個包裝好的function被call的時候也傳了一些參數進去的話，就會在後面再接下去接收。
* 好難縮，看看例子吧。
* Example 2:
    ```javascript=
    function someApiCode ( callback ) {
        
        const countArea = callback ( 5, 5 );
        console.log ( countArea );
    }

    function area ( name, width, height ) {
        
        console.log ( this.type );
        console.log  ( name );
        
        return width * height;
        
    }

    const obj = {
        type: "square"
    };
    
    let func = area;
    let bindFunc = area.bind ( obj, "Tony" );

    someApiCode ( func );        // output: undefined
                                 //         5
                                 //         NaN

    someApiCode ( bindFunc );    // output: "square"
                                 //         "Tony"
                                 //         "25"
    ```
    > 先看有`bind`的那個部分，因為在呼叫`bind`的時候，有傳了第二個參數，所以他會接到呼叫`area`的時候的第一個參數`name`，然後又從`someAPiCode`那裏傳了剩下兩個參數`width`和`height`。
    > 再來看一般那樣呼叫，因為從`someaApiCode`裡面呼叫時，直接傳了兩個5過去，所以會對到`area`裡面的`name`和`width`，所以就會印出那樣的結果。