[JavaScript] functionとarrow関数でのthisの挙動

前回まではレキシカル環境とクロージャについてお話ししてきました。

今回はfunctionとarrow関数でのthisの挙動の変化について書いていこうかと思います。

今回はカイージくんは登場しません。予めご了承ください。

⇩カイージくんとのお勉強はこちらをご覧ください⇩

https://qiita.com/shima14142/items/35d47c65799251e73fd9

https://qiita.com/shima14142/items/ba57d6f4038681819b5a

## 本題:thisとは
`this`は関数やメソッドがどのオブジェクトから呼び出されたかを示します。

通常の関数では、`this`は関数が呼び出されたコンテキストによって決まります。例えば、オブジェクトのメソッドとして呼び出された場合、`this`はそのオブジェクトを指します。

~~~js
const obj = {
    value: 42,
    regularMethod: function() {
        console.log(this.value); // this は obj を指す
    }
};

obj.regularMethod(); // 42
~~~

非strict モードでは、グローバルスコープで`this`を使用すると、グローバルオブジェクト（ブラウザ環境では window）を指しますが、`use strict`モードでは`this`は`undefined`になります。

また、通常の関数として呼び出され時、以下のようになります。

~~~js
const obj = {
    value: 42,
    method: function() {
        const innerFunction = function() {
            console.log(this.value); 
        };
        innerFunction();
    }
};

obj.method(); // グローバルオブジェクト（非 strict モード）、または `undefined`（strict モード）

~~~

同様に、上記の例では、`innerFunction`は通常の関数として呼び出されるため、`this` はグローバルオブジェクトを指します（非 `strict` モードの場合）。`strict` モードでは `undefined` になります。
***
レキシカル環境は関数がどこで定義されたかによって決まるスコープチェーンである一方、アロー関数を使用した際は`this` 自体はレキシカル環境（スコープチェーン）を作りません。

以下のコードを見てみましょう。
~~~js
const obj = {
    value: 42,
    method: function() {
        const innerFunction = () => {
            console.log(this.value); // ここでの `this` は外側のスコープから継承される
        };
        innerFunction();
    }
};

obj.method(); // 42
~~~
アロー関数を使用した場合、`this` は外側のスコープ（この場合は `method` 内のスコープ）から継承され、`obj` を指します。

上記のコードを全てアロー関数で書いた場合はどうなるでしょうか。
~~~js
const obj = {
    value: 42,
    method: () => {
        const arrowFunction = () => {
            console.log(this.value); // ここでの `this` はグローバルオブジェクト（非 strict モード）や `undefined`（strict モード）を指す
        };
        arrowFunction();
    }
};

obj.method(); // undefined (strict モードの場合) または グローバルオブジェクトの `value` (非 strict モードの場合)
~~~

## CallBck関数との兼ね合い
通常の関数をコールバックとして使用すると、その`this`は呼び出し時のコンテキストに依存します。

以下で実行してみましょう。
~~~js
const obj = {
    value: 42,
    method: function(callback) {
        callback();
    }
};

function regularFunction() {
    console.log(this.value);
}

obj.method(regularFunction); // undefined
~~~
`regularFunction`の`this`はグローバルオブジェクトを指すので、残念ながら期待通りの結果にはなりませんでした。

ここで、アロー関数は定義されたときの`this`を継承するので、コールバックとして使用してみましょう。
~~~js
const obj = {
    value: 42,
    method: function(callback) {
        callback();
    }
};

const arrowFunction = () => {
    console.log(this.value);
};

obj.method(arrowFunction); // undefined
~~~
しかし、`arrowFunction`が定義されたときのスコープに`value`が存在しないため、`undefined` になります。

そこで、正しい this を指すようにするためには、アロー関数をオブジェクトのメソッド内で定義してみましょう。

~~~js
const obj = {
    value: 42,
    method: function() {
        const arrowFunction = () => {
            console.log(this.value); // this は obj を指す
        };
        arrowFunction();
    }
};

obj.method(); // 42
~~~
無事、辿り着けましたね。

もし、通常の関数でもコールバックで同じようにthisを求めたい時はどうすればいいのでしょうか。

ここでは`bind`メソッドを使って明示的に繋げる方法をご紹介します。

`bind`メソッドは、定義された関数に対して、thisを代入できるメソッドです。また、その名の通り関数などをbind（紐づけ）することができます。
~~~js
const obj = {
    value: 42,
    method: function(callback) {
        callback();
    }
};

function regularFunction() {
    console.log(this.value);
}

obj.method(regularFunction.bind(obj)); // 42
~~~





時間があれば、わかりやすい図とかも用意するかもしれません。