Javascriptの標準組み込みオブジェクトのFunctionのインスタンスメソッドcall(),apply(),bind()について

なんとなくで使っていたので、整理を兼ねて文字に起こします。

# はじめに
Javascriptには、標準組み込みオブジェクト(Standard built-in objects)というグローバル領域にあるオブジェクトがあります。
この標準組み込みオブジェクトにオブジェクトの基本となるオブジェクト、`Object`,
`Function`,`Boolean`,`Symbol`があります。

今回はこの中の`Function`オブジェクトについて、深掘りしていきます。
Javascriptの全ての関数はこの`Function`オブジェクトであり、 `Function`オブジェクトは `functions`のメソッドを持ちます。

# thisについて
`Function`のメソッドで使うためには`this`を理解しておく必要があります。
個人的に、下記が一番わかりやすかったです。

https://qiita.com/takkyun/items/c6e2f2cf25327299cf03

thisはオブジェクト自身を指し、`.`の前のオブジェクトが指定されます。

関数の呼び出しをした時、オブジェクトで実行している場合、そのオブジェクトをthisとして参照できます。
オブジェクトを指定しない場合は、グローバルオブジェクトまたはundefinedが指定されます。
別のオブジェクトを指定した場合、その別のオブジェクトがthisとして参照されます。

```js
// 1. オブジェクトを指定している
const obj1 = {
    prop1: 1,
    func1: function() { console.log(this) }
};
obj1.func1(); 
// => {prop1: 1, func1: ƒ}

// 2. オブジェクトを指定していない
const func2 = obj1.func1;
func2(); 
// => undefinedまたはグローバルオブジェクト (ブラウザで実行している場合はwindow)

// 3. 別のオブジェクトを指定する
const obj2 = {
    prop2: 2
}
obj2.func2 = obj1.func1;
obj2.func2(); 
// => {prop2: 2, func2: ƒ}
```

# 標準組み込みオブジェクトのFunctionのインスタンスメソッド
下記のメソッドが用意されています。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function#instance_methods

### Function.prototype.call()
第一引数にthisの値、第二引数以降は呼び出し先の引数として渡されて、関数を呼び出せます。
```js
const obj1 = {
    prop1: 1,
    func1_1: function(prop1_1) { console.log(prop1_1, this) },
    func1_2: function(prop1_1, prop1_2) { console.log(prop1_1, prop1_2, this) }
};
const obj2 = {
    prop2: 2
};

obj1.func1_1.call(obj2, 3);
// => 3 {prop2: 2}

obj1.func1_1.call(obj2, 3, 4);
// => 3 {prop2: 2}

obj1.func1_2.call(obj2, 3, 4);
// => 3 4 {prop2: 2}

obj1.func1_2.call(obj2, [3, 4, 5, 6], 7);
// =>  [3, 4, 5, 6] 7 {prop2: 2}

obj1.func1_1.call(1, 3); // 数値を指定するとNumberのオブジェクトとして指定される
// => 3 Number {1}

obj1.func1_1.call('1', 3); // 文字列を指定するとStringのオブジェクトとして指定される
// => 3 String {'1'} 

obj1.func1_1.call(null, 3); // nullやundefinedを指定すると、
// => 3 undefinedまたはグローバルオブジェクト
```

### Function.prototype.apply()
第一引数にthisの値、第二引数は呼び出し先の引数を列挙したArrayを指定して、関数を呼び出せます。
```js
const obj1 = {
    prop1: 1,
    func1: function(prop) { console.log(prop, this) }
};
const obj2 = {
    prop2: 2
}

obj1.func1_1.apply(obj2, 3);
// => Arrayでないので、error

obj1.func1_1.apply(obj2, [3]);
// => 3 {prop2: 2}

obj1.func1_1.apply(obj2, [3, 4]);
// => 3 {prop2: 2}

obj1.func1_2.apply(obj2, [3, 4]);
// => 3 4 {prop2: 2}
```

### Function.prototype.bind()
第一引数にthisの値して、新しく関数を作成します。

```js
const obj1 = {
    prop1: 1,
    func1: function(prop) { console.log(prop, this) }
};
const obj2 = {
    prop2: 2
};

const func1_1_bind = obj1.func1_1.bind(obj2);
const func1_2_bind = obj1.func1_2.bind(obj2);

func1_1_bind(3);
// => 3 {prop2: 2}

func1_1_bind(3, 4);
// => 3 {prop2: 2}

func1_2_bind(3, 4);
// => 3 4 {prop2: 2}
```


### 使い道を考える
下記のような、classのインスタンスメソッドをそのインスタンス外で使いたい時などで使える

```js
class Animal {
    name = 'animal';
    display_name() {
        console.log(this.name)
    }
}

class Fish {
    name = 'fish';
}

const animal = new Animal();
const display_name1 = animal.display_name;
// 1. 別のオブジェクトのプロパティでメソッドを使う
const fish = new Fish();
display_name1.call(fish);
// => fish

// 2. インスタンスメソッドをそのインスタンス外で使う
const display_name2 = animal.display_name.bind(animal);
display_name2();
// => animal
```

# 終わり
調べるついでにQiita書こうと思うと、理解する意欲が変わるので今後続けていきたい

# 参照

[MDN Web Docs Standard built-in objects Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function#instance_methods)

[JavaScript の this を理解する多分一番分かりやすい説明](https://qiita.com/takkyun/items/c6e2f2cf25327299cf03)