85
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

JavaScriptの闇 thisへ挑む

はじめに

今回はJavaScriptの闇... thisについて、様々な角度で挑みたいと思います!

【YouTube動画】JavaScriptの闇 this
JavaScriptの闇 this

thisとは

thisは関数の呼び出し元へのリンクです。

例えば、以下の場合test.getName()はtaroを返します。

thisは関数getNameで呼び出されています。その関数getNameはtestオブジェクトの関数なので、this = testオブジェクトになります。
関数getName()のthisをtestオブジェクトに変え、test.name = taroとなります。

const test = {
  name: 'taro',
  getName: function() {
    return this.name;
  }
}

グローバルなthis

関数の読み出し元を指定しない場合はWindowになります。
それを確認してみましょう。

以下2つを定義しておきます。

まず、obj.sayThis()を考えます。
sayThis()はobjオブジェクトから呼び出されているので、関数sayThis内のthisはobjオブジェクトになります。
ということで、obj.sayThis()は { name: 'taro' } を返します

次に、sayThis()を考えます。
こちらは特に呼び出しているオブジェクトがないため、Windowになります。
ちなみに、strictモードで実行すると、undefinedになります。

// メソッド
const sayThis = function() { console.log(this) }

// オブジェクト
const obj = { name: 'taro' }

コンストラクタでのthis

コンストラクタではnewでオブジェクトを作成でき、呼び出し元が定まります。

以下のように定義しておきます。

yamadaの方ではnew Personによりオブジェクトが作成されるので、yamada.nameはtaroを返します。
しかし、tanakaの方はオブジェクトが作成されていないので、name of undefinedエラーになります。

const Person = function(hoge) { this.name = hoge; }

const yamada = new Person('taro')
const tanaka = Person('taro')

プロトタイプメソッド内でのthis

以下のように定義しておきます。
ここで、yamada.getName()とすると、taroが返ります。
ちなみに、Person.getName()の場合はPerson.getName is not a functionになります。

const Person = function(hoge) { this.name = hoge; }
Person.prototype.getName = function() { return this.name; }

const yamada = new Person('taro')

対して、次のようにprototypeをなくした場合は、yamada.getName is not a functionになります。
また、Person.getName()の場合、Personが返ります。

const Person = function(hoge) { this.name = hoge; }
Person.getName = function() { return this.name }

const yamada = new Person('taro')

入れ子関数でのthis

入れ子関数にすると、定義元はどうなるでしょう。

以下を定義して、test.sayHello()を実行すると、上から { sayHello: f }, Windowになります。
最初のthisの呼び出し元はsayHelloで、2番目のthisは呼び出し元が明示されていないためです。

const test = {
  sayHello: function() {
    console.log(this)
    const func = function() {
      console.log(this)
    }
    func()
  }
}

arrow関数でのthis

入れ子関数でもarrow関数にすると、thisの呼び出し元が定まります。

そのため以下の場合、test.sayHello()は、{ sayHello: f }, { sayHello: f } になります。

const test = {
  sayHello: function() {
    console.log(this)
    const func = () => {
      console.log(this)
    }
    func()
  }
}

まとめ

今回はJavaScriptで迷いやすいthisについて解説していきました!
なるほど分からんと思った方、ぜひコンソール画面などで遊んでみてください!

twitteryoutubeでのコメントもお待ちしています!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
85
Help us understand the problem. What are the problem?