# Explain Function.prototype.bind.
## 一、名詞定義、概念
bind() 方法,javascript中function物件內建的method。
會建立一個新函式。該函式被呼叫時,會將 this 關鍵字設為給定的參數。
使用這個方法,並不需要給與對應的參數或參數陣列,然而他也不會回傳你函數執行結果,而是給你一個「綁定this的函數」,一但被綁定,其this無法再被修改。
寫React的時候,bind只會出現在class component的寫法。因為function component(hook)不會用到this,所以也不用bind。
## 二、機制運作方式
### 建立綁定函式
1. this 是動態特性:在全域環境下的this V.S 函式環境下的this (參考:版本二 Javascript this)
3. bind() 幫我們建立了一個新的 function ,並且當我們執行時這個 function 的 this 是指向 foo,而不是全域。
```
var foo = {
x: 3
}
var bar = function () {
console.log(this.x);
}
bar(); // undefined //this =>window
//等同於 window.bar()
var boundFunc = bar.bind(foo);
//等同於 foo.bar()
boundFunc(); // 3
```
<hr/>
### 使用綁定函式
### -參數
**function.bind(thisArg[, arg1[, arg2[, ...]]])**
* **第一個參數(thisArg):**
1. 參數傳遞給目標函式的值
2. 任何傳遞值都會轉成物件
3. 當為空、null、undefined時,執行作用域的this將背是為新函數的thisArg
* **第一個之後的參數(arg1, arg2, ...):**
1. 當目標函數被調用時,被預置入綁定函數的參數列表中的函數
### -返回值
* 返回一個新的函式
* 該函式具有指定的this的值和初始參數
* bind() 被調用時,這个新函数的 this 被指定成 bind() 的第一個参数
* 其餘参数將作为新函数的参数,供調用時使用。
bind()方法会把传入它的第一个实参绑定给f函数体内的 this,从第二个实参起,将依此传递给原始函数,因此 {x:1}传递给this ,2传递给形参y,m(3) 调用时的3 传递给形参z。
```
function f(y,z){
return this.x+y+z;
}
var m=f.bind({x:1},2)
console.log(m(3)); // 6
```
<hr/>
### Function.prototype.bind() 內部運行機制
* 創建新的函式-**綁定函式 bound function, BF**
* 呼叫綁定函式會執行**包裝函式(wrapped function)**,包裝原函數對象(指向的物件),調用綁定函數
* 绑定函数具有以下内部属性
1. **TargetFunction:**
包裝函式的對象
2. **This:**
調用包裝函式時,作為this所傳遞的值
3. **Arguments:**
對於包裝函式作任何調用時,都會優先用列表內的元素,填充到參數列表中
4. **Call:**
與物件相關的執行代碼,透過表達式調用。包含this值和傳遞到函式的Arguments的列表

<hr/>
<hr/>
## 補充:function 三個方法, bind()、apply()、call()
| | bind | call | apply |
| -------- | -------- | -------- |-------- |
| 語法 | wtf.bind(obj)(1, 2); | wtf.call(obj, 1, 2); |wtf.apply(obj, [1, 2]);
| 用法 | 使用給定的this參數,但不一定要給與對應的參數或參數陣列| 使用給定的this參數以及分別給定的參數來呼叫某個函數|只允許兩個變數傳入,第二個變數等於是原始function的參數陣列。
| 回傳 | 綁定 this 後的原函數 | function執行結果 |function執行結果
```
function wtf(argv0, argv1) {
console.log(this.v, argv0, argv1);
}
var obj = { v: 'I am v of obj' };
// We hope we can get the obj this
// so assign function in obj
obj.func = wtf;
obj.func(1, 2); // I am v of obj 1 2
// or we just tell the function what `this` in first param
wtf.apply(obj, [1, 2]); // I am v of obj 1 2
wtf.bind(obj)(1, 2); // I am v of obj 1 2
wtf.call(obj, 1, 2); // I am v of obj 1 2
```
## 三、案例說明
### 使用bind的時機
以下情況產生無法取得this的問題:
實際執行我們可以發現 laterHello 的這個方法,他的 timer callback 拿不到正確的 this的問題。
```
class dog{
constructor(name){
this.name = name;
}
sayHello(){
console.log('Hello I am ',this.name);
}
laterHello(){
setTimeout(function(){
console.log('(1 sec...) Hi!, I am',this.name)
}, 1000);
}
}
let boo = new dog('fongki');
boo.sayHello(); // Hello I am fongki
boo.laterHello(); // (1 sec...) Hi!, I am undefined
```
#### 三種思路
* **Self大法駕到**
把 this 儲存成一個變數,接著即便切換Context 還是可以參考到這個物件。
使用閉包的概念:
> 閉包:
>1. 它是一個 function。
>2. 它產生了一個 Context ,概略的說就是幫你記錄上一層有宣告的變數。
```
laterHello() {
var self = this;
// let keep the class's this
setTimeout(function() {
console.log('(1 sec...) Hi!, I am', self.name);
// In the context, we can access `self`
// so we could get `self.name`
}, 1000);
}
```
* **Binding大法**
透過創建綁定函式來解決
不需要改變回調函數本身的區塊,而是在外頭直接告訴callback該用哪個作為正確的this。
```
laterHello() {
setTimeout(
function() {
console.log('(1 sec...) Hi!, I am', this.name);
}.bind(this),
1000
);
}
```
* **Arrow Function**
箭頭函數 多數時候一般函數無異,但是最大的差別在於 — 其 this 完全綁定在語彙上的位置,也就是說在 arrow 裡面的 this 永遠都是語意上的 this ,不管是誰呼叫他,或是被如何 bind 、 call 、 apply ,他永遠都是拿到原先作用域的 this 。
```
laterHello() {
setTimeout(() => {
console.log('(1 sec...) Hi!, I am', this.name);
}, 1000);
}
```
## 四、實際應用
[老師課程:React其他重要主題-事件處理](https://www.udemy.com/course/javascript-es6-react-redux/learn/lecture/9088514#overview)
```
class MyHead extends React.Component{
render(){
return (
//把組建實體bind到事件處理
<div onClick={this.clickHandler.bind(this)}
className={'head-'+this.props.level}
>Hello Component</div>;
)}
clickHandler(e){
console.log("觸發點擊事件");
console.log(this.props);
//利用this取得當前組件,進一步取得props或state
}
}
```
[codepen 簡易應用1-onClick事件](https://codepen.io/beckyhung37/pen/abWMgeJ)
[codepen 簡易應用2-onChange事件](https://codepen.io/philbaker/pen/XgGLVj)
## 五、參考來源
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
https://ithelp.ithome.com.tw/articles/10155643
https://www.cnblogs.com/leoo2sk/archive/2010/12/19/ecmascript-scope.html#comment_tip
https://realdennis.medium.com/javascript-%E8%81%8A%E8%81%8Acall-apply-bind%E7%9A%84%E5%B7%AE%E7%95%B0%E8%88%87%E7%9B%B8%E4%BC%BC%E4%B9%8B%E8%99%95-2f82a4b4dd66
https://realdennis.medium.com/javascript-%E8%81%8A%E8%81%8Acall-apply-bind%E7%9A%84%E5%B7%AE%E7%95%B0%E8%88%87%E7%9B%B8%E4%BC%BC%E4%B9%8B%E8%99%95-2f82a4b4dd66
https://stackoverflow.com/questions/53215067/how-can-i-bind-function-with-hooks-in-react