JavaScriptのthisを探して

2021-07-17

概要

JavaScriptでよく見かけるthisというワード。
これは一体何者で、何がthisなのか疑問に思う人は少なくないはずです。

実際、thisは何を示しているのかわからないまま使用すると痛い目にあいます。

今回はthisについて考えていきましょう。

thisとは

スクリプト内のどこからでも使用可能な特別な変数です。
それゆえにthisが何を示しているのかが不明瞭になり、バグを生み出す可能性があります。

objectを指し示すthis

よくみるパターンを見てみます。

const obj = {
    a: 'aaa',
    func: function() {
        console.log(this.a)
    }
}

obj.func() // aaa

このthisは変数objを参照しています。
呼び出し元によってthisの内容も変わってきます。

今回は変数objからの呼び出しなので、ログにはaaaと出ます。

addEventListenerメソッド

こちらもよく見かけると思います。
DOMを取得し、そのDOMを参照するthisです。

const button = document.querySelector('.js-button')

button.addEventListener('click', function() {
  console.log(this)
})

ミスケース

ここでは思わぬthisを招いたケースを紹介します。

ケース1 setTimeoutのthisの行方

例えばこんなコードを書いたとします。

const obj = {
    a: 'aaa',
    func: function() {
        console.log(this)
    }
}

// object window
setTimeout(obj.func, 1000)

最初のthisはobjを示しますが、setTimeoutではwindowオブジェクトを指しています。

setTimeoutによる実行コードは、呼び出された関数とは別のコンテキストから呼び出されるのです。
よって、この場合のthisはwindowオブジェクトを指すようになります。

この対策としては、二つあります。

解決策1 bindメソッド

あらかじめしようするメソッドに対し、bindを使用してthisの参照先を束縛すれば大丈夫です。

const obj = {
    a: 'aaa',
    func: function() {
        console.log(this)
    }
}

const func = obj.func
// thisをbindしてobjで固定する
const bindFunc = func.bind(obj)
setTimeout(bindFunc(), 1000)

解決策2 アロー関数の使用

const obj = {
    a: 'aaa',
    func: function() {
      // アロー関数自体にthisを持たないので実行コンテキストに依存しない
      setTimeout(() => {
        console.log(this)
      }, 1000)
    }
}

obj.func()

ケース2 アロー関数のthis

アロー関数ではthisを持ちません。

それゆえに束縛する、といった表現がなされます。
thisがないので定義された時点でthisが決定されます。

例えばこのようなコードではthisは、クライアントサイドではwindowオブジェクトを示します。

const obj = {
    a: 'aaa',
    // アロー関数はthisを持たないので結局windowオブジェクト参照になってしまう
    func: () => {
       console.log(this)
    }
}

obj.func()

これは極端ですが、以下の方法で解決できます。

const obj = {
    a: 'aaa',
    func: function() {
      const arrowFunc = () => {
        // このthisはfuncのthisを参照することになる
        // よってthisはobjを参照できる
        console.log(this)
      }
      return arrowFunc
    }
}

obj.func()()

func関数のなかにアロー関数で定義されているarrowFunc関数があります。
arrowFunc関数だけではthisを持たないので、func関数のthisを参照するようになります。この地点でthisが束縛されています。

結論

thisは魔法のように示す内容を変化させます。
ですがアロー関数のようにthisを持たない関数だと、予期せぬバグを生み出す可能性があります。

thisがどこを示しているか確認しながらコードを買いていくことをお勧めします。

参照

this
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/this

setTimeout
https://developer.mozilla.org/ja/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#the_this_problem

運営について

Natural Tearoomはシステム開発会社フロントエンドエンジニアがんちゃんが運営するメディアです。
フロントエンド技術を中心に発信しています。

· プライバシーポリシー

SNS

© 2021 天然珈琲店