Javascriptのfunction()とアロー関数でのthis

# はじめに

普段C#で開発を行っていますが、最近Web開発技術も勉強中です。
その中で、Javascriptのthisで混乱したことがあったので整理します。

# Javascriptのthis

例えば、ブラウザのコンソールで以下のコードを書きます。

```javascript
let user = { 
    firstName: "John",
    sayHi: function(){
        console.log( this.firstName )
    }
 };
```

この場合、user.sayHi()を実行すると、コンソールで"John"を表示できます。

今度は以下のようにアロー関数内でthisを使ってみます。
```javascript
let user = {
  firstName: "John",
  func: () => console.log(this.firstName)
};
```
この場合、user.func()を呼んでもコンソールで"undefined"が表示されました。

thisを確かめるため、以下のコードに書き換えました。
```javascript
let user = {
  firstName: "John",
  func: () => console.log(this)
};
```
上記を試すと、コンソールにWindowが表示されました。
アロー関数の場合、thisはWindowを指しますが、WindowはfirstNameを持っていないため、undefinedとなるようです。

function()を使用する場合と、アロー関数を使用する場合で、thisの指し先が異なっています。
MDNには以下の記載がありました。(MDNの該当箇所は[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/this#:~:text=%E3%81%BB%E3%81%A8%E3%82%93%E3%81%A9%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81this%20%E3%81%AE%E5%80%A4%E3%81%AF%E3%81%A9%E3%81%AE%E3%82%88%E3%81%86%E3%81%AB%E9%96%A2%E6%95%B0%E3%81%8C%E5%91%BC%E3%81%B0%E3%82%8C%E3%81%9F%E3%81%8B%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E6%B1%BA%E5%AE%9A%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%20(%E5%AE%9F%E8%A1%8C%E6%99%82%E7%B5%90%E5%90%88)%E3%80%82%E3%81%93%E3%82%8C%E3%81%AF%E5%AE%9F%E8%A1%8C%E6%99%82%E3%81%AB%E4%BB%A3%E5%85%A5%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AF%E3%81%A7%E3%81%8D%E3%81%9A%E3%80%81%E9%96%A2%E6%95%B0%E3%81%8C%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%95%E3%82%8C%E3%82%8B%E3%81%9F%E3%81%B3%E3%81%AB%E7%95%B0%E3%81%AA%E3%82%8B%E5%8F%AF%E8%83%BD%E6%80%A7%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82))
>ほとんどの場合、this の値はどのように関数が呼ばれたかによって決定されます (実行時結合)。これは実行時に代入によって設定することはできず、関数が呼び出されるたびに異なる可能性があります。

アロー関数の場合、MDNには以下の記載がありました。(MDNの該当箇所は[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/this#:~:text=%E3%82%A2%E3%83%AD%E3%83%BC%E9%96%A2%E6%95%B0%E3%81%A7%E3%81%AF%E3%80%81this%20%E3%81%AF%E3%81%9D%E3%82%8C%E3%82%92%E5%9B%B2%E3%82%80%E6%A7%8B%E6%96%87%E4%B8%8A%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AE%20this%20%E3%81%AE%E5%80%A4%E3%81%8C%E8%A8%AD%E5%AE%9A%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7%E3%81%AF%E3%80%81%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%8C%E8%A8%AD%E5%AE%9A%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82))

>アロー関数では、this はそれを囲む構文上のコンテキストの this の値が設定されます。グローバルコードでは、グローバルオブジェクトが設定されます。

function()の場合は実行時にthisを決定し、アロー関数の場合は、呼ばれ方に寄らず、常に定義した場所でのthisを参照するという解釈をしました。

実行時の呼ばれ方というのをもう少し詳しく見るため、以下のようなコードを書いた場合を考えます。
```javascript
let user = { firstName: "John" };
let admin = { firstName: "Admin" };
function sayHi() {
  console.log( firstName.name );
}
user.f = sayHi;
admin.f = sayHi;

sayHi();   // "undefined"が表示される
user.f();  // "John"が表示される
admin.f();　// "Admin"が表示される
```

どのオブジェクトから呼ばれているかによってthisが変わるということのようです。
オブジェクトに設定せず、コンソール上でただsayHi()を呼ぶ場合、呼び出しているオブジェクトがグローバルコンテキスト（ブラウザ上だとWindow）になり、グローバルでfirstNameプロパティを設定していないため、undefinedとなります。

気になったので以下の場合を試しました。
```javascript
let user = {
  firstName: "John",
  func: () => alert(this.firstName),
  sayHi: function(){
        this.func();
    }
};

user.sayHi(); // alertで"undefined"が表示される
```

function()の中のthisはuserを指せているため、alertの表示自体は出ますが、アロー関数のthisは定義時のthisを参照する、つまり、今回の場合はグローバルオブジェクトのWindowを指します。
グローバルオブジェクトでは特にnameプロパティを定義していないため、undefinedが表示されました。

# さいごに

thisの扱い方、ややこしかったですが、いろいろ試して整理できました。