🗂

【JS】thisについて

2021/10/05に公開

今回はみんなの混乱の元である、thisについて解説していきます。

thisは一応様々なコンテキストで使えますが、基本的にはメソッド内での挙動とクラス内での挙動を把握していればOKです。

そして、今回は関数内の挙動に絞って解説していきます。

関数(メソッド)内でのthis


thisの挙動はアロー関数とそれ以外の関数定義の仕方によって異なります。

なので、それらを別々に解説していきます。

アロー関数以外

アロー関数以外のthisは、メソッドのベースオブジェクトを参照します。

ベースオブジェクトとは、呼び出し元のオブジェクトのことです。

この場合は、thisの参照が実行によって異なるので問題です。

例えば、以下のようにそのまま関数として実行した場合と、メソッドとして実行した場合はthisの挙動が変わってしまいます。


function fn1() {
  return this;
}

const obj = {
  props: "hoge",
  method2: fn1,
};
// undefined
console.log(fn1());
// {props: "hoge", method2: ƒ fn1()}
obj.method2();

この実行ごとにthisの値が変わってしまうという問題は以下の3つのメソッドを使うことで解決します。

  1. call
  2. apply
  3. bind

それぞれの扱い方は以下の通りです。

メソッド 使い方
call 第一引数にthisの値、それ以降に関数の引数を渡す
apply 第一引数にthisの値、それ以降に関数の引数を配列で渡す
bind thisや関数の引数を固定して新しい関数を作れる

function fn1(msg) {
  return console.log(msg, this);
}

const obj = {
  props: "hoge",
  method2: fn1
};

// hello1 {props: "hoge", method2: ƒ fn1()}
fn1.call(obj, "hello1");
// hello2 {props: "hoge", method2: ƒ fn1()}
fn1.apply(obj, ["hello2"]);
const bindFn = fn1.bind(obj, "hello3");
// hello3 {props: "hoge", method2: ƒ fn1()}
bindFn();

また、関数内のthisにおいては、もう1つの問題があります。

それはコールバック関数を使った場合に、thisを参照できなくてなってしまうということです。

以下がその例になります。


const obj = {
  props: "hoge",
  method2() {
    // {props: "hoge", method2: ƒ method2()}
    console.log(this);
    const fn = function () {
      // undefined
      console.log(this);
    };
    fn();
  }
};

obj.method2();

なぜこうなるのかと言うと、fnという関数は飽くまで関数でありメソッドではないからです。

要するにfnという関数にはベースオブジェクトが無いため、undefinedとなってしまうのです。

対策方法としては、thisを変数として入れてあげればOKです。


const obj = {
 props: "hoge",
 method2() {
   const that = this;
   const fn = function () {
     // {props: "hoge", method2: ƒ method2()}
     console.log(that);
   };
   fn();
 }
};

obj.method2();

また、もう1つの対策としてはアロー関数を使うという方法があります。

それについては次の章で詳しく解説していきます。

アロー関数

アロー関数におけるthisがどの値を参照するかは、関数の定義時に決まります。

そして、アロー関数とそれ以外の関数で大きく違うことは、thisを暗黙的な引数として受けつけないということです。


const obj = {
  props: "hoge",
  method2: () => {
    // undefined
    console.log(this);
  }
};

obj.method2();

そのため、アロー関数内にはthisが定義されていません。

なので、このとき変数におけるスコープチェーンの仕組みと同様で、thisは外側のスコープのthisを参照します。

なので、アロー関数はメソッド内でのコールバック関数に使えます。


const obj = {
  props: "hoge",
  method2() {
     // {props: "hoge", method2: ƒ method2()}
    console.log(this);
    const fn = () => {
       // {props: "hoge", method2: ƒ method2()}
      console.log(this);
    };
    fn();
  }
};

obj.method2();

なので、アロー関数を上手く使うことでバグを避けられるコードを書くことができるわけです。

おわりに


今回は、javascriptのつまずきポイントであるthisについて解説してきました。

意外とそこまで使う機会無いので、忘れたらまたこの記事に戻ってくればOKです。

最後に宣伝です。

0からエンジニアになるためのノウハウをブログで発信しています。
https://hinoshin-blog.com/

また、YouTubeでの動画解説も始めました。
YouTubeのvideoIDが不正ですhttps://www.youtube.com/channel/UCqaBUPxazAcXaGSNbky1y4g

インスタの発信も細々とやっています。
https://www.instagram.com/hinoshin_enginner/

興味がある方は、ぜひリンクをクリックして確認してみてください!

おわり

Discussion