# `call`、`apply`、`bind`
###### tags: `javascript`
這三個method是`Function`物件最重要的三個method。
> 如果你看不懂上面那句話在銃三毀,請先去看funciton那一篇。
他們最大的共通點就是改變`this`的指向。`call`和`apply`都是拿來呼叫一個function,而`bind`的則是拿來包裝一個function。
## `call` [](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call)、`apply` [](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` [](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`,所以就會印出那樣的結果。