前言
這篇文章我們要討論三個函式 (call、apply、bind),這是用來控制特殊關鍵字 this 指向的函式。
call()、apply()、bind()
在前面的篇章提到,在執行環境中有變數環境、外部參考,還有 JavaScript 幫我們設定好的 this 變數。

我們已經看過 this 預設指向全域物件、也可以指向包含函式的物件,然而之前我們提到控制 this 的方式,是使用一個變數來儲存 this 指向的位址。
而這一篇提到的三個函式將幫助我們更有效率的控制 this 。
函式是特殊形態的物件,它具有
- 名稱屬性 - 可匿名的名稱屬性
 - 程式屬性 - 可包含程式碼,而程式屬性是可以被呼叫的,所以可以被執行。
 
函式就是物件,所以函式可以有屬性和方法,而且所有函式都有 call()、apply()、bind() 方法

bind()
我們先建立一個初始的範例,如下:
1  | var person = {  | 
- 我們建立了 
person物件,並且在裡面建立了getFullName方法。 - 方法內的 
this指向person物件,並回傳fullName。 - 宣告了 
logName並指向一個匿名函式,但函式內的this此時是指向全域物件windows,因此執行logName函式後得到undefined。 
這時就是 bind() 出場的時候了,將程式碼改成以下:
1  | var person = {  | 
我宣告了 logPersonName 並且取用 logName 的 bind 方法,然後傳入想要 this 變數指向的物件,接著 bind 方法會回傳一個新的函式,它會複製 logName 函式,並且設定為一個新的函式物件。
所以當呼叫 logPersonName 函式時,因為 this 已經指向 person 物件,所以輸出就如同預期。
甚至也可以寫得更簡潔,像是這樣:
1  | var person = {  | 
bind 方法會產生 logName 函式的拷貝,並且將 this 指向為我們指定的物件。
1  | var person = {  | 
bind 方法會將函式完整的拷貝下來。

這就是 bind 的作用,創造拷貝函式,然後將 this 指向到某個物件。
call()
接續上面的範例
1  | var person = {  | 
call 方法可以讓我們決定 this 要指向哪個物件、也可以傳入參數,而第一個參數就是決定 this 要指向的物件。基本上就跟 () 用法一樣,但 call 方法允許控制 this 的值。
與 bind 方法不同的地方是,call 方法並不是創造函式的拷貝並等待呼叫,而是直接執行並且改變 this 的指向。
apply()
接續上面的範例
1  | var person = {  | 
apply 方法與 call 方法雷同,只是控制 this 之後的傳入參數,部分略有不同。
call方法允許傳入各種型別的值,但是apply方法只接受陣列作為參數。
所以這兩個方法可以根據函式的情況來使用。
不使用括號來達成立即執行函式
看過了 apply 方法與 call 方法,我們可以這麼寫:
1  | (function(lang1, lang2){  | 
所有的函式都可以使用 apply、call、bind 方法。
實際上的使用
這些方法可以如何地在實際開發上使用呢?
函式借用 (function borrow)
1  | var person = {  | 
我們創造了兩個物件,一個 person 物件、一個 person2 物件,但是在 person2 物件內沒有 getFullName 方法。
可以透過 call 、 apply 方法達成函式借用,即使 person2 物件內沒有 getFullName 方法,透過改變 this 的指向,也可以輸出 person2 的物件內容。
函式柯里化 (function curring)
這個部分跟 bind 方法的特性有關,如果我們傳入參數給 bind,會有不太一樣的事情發生,讓我們來觀察。
1  | function multply(a, b){  | 
我寫了一個會回傳 a * b 的 multply 函式,並且使用 bind 方法拷貝一份新的函式給 mulipleByTwo ,在此 this 的指向不重要,重要的是傳入的參數。
bind方法會將傳入的參數設定為一個定值。
以例子來說 multply.bind(this, 2) 就好比這樣:
1  | function multply(a, b){  | 
而在 bind 內設定了傳入的參數後,我們呼叫的函式所帶入的參數就會變成另一個,以本例來說就是 b 。
因此輸出就是 2 * 4 = 8
如果 bind 填入了所有參數呢?
1  | function multply(a, b){  | 
像這樣,使用 bind 方法拷貝一份新的函式給 mulipleByThree ,並且填入 a 跟 b 參數。
當我們呼叫 mulipleByThree 帶入參數時,受到 bind 影響,所以無論帶入什麼,輸出的結果都是 12 。
於是 函式柯里化 (function curring) 的意思就是建立一個函式的拷貝,並設定不可變的預設參數。
函式柯里化主要用於數學的運算,可以寫個基本的函式,然後根據這個函式放入預設參數,用以減少需要填入的參數,這是一種 bind 的用法。