1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ゲームを作りながら学ぶ!JavaScript レベルアップ講座 part3

Last updated at Posted at 2020-12-08

こんにちは、Yuiです。

今回は前回に引き続きJavaScript道場で学んだthisについて解説をしていきます。

thisとは何かを理解する

まずは前回使ったこちらのコードを見てください。

var personA = {
  name: 'Bob',
  greeting: function() {
    alert('Hi! I\'m ' + this.name + '.');
  }
}

この中のthisが何なのかを確認する前に、thisを抜いたらどうなるのかを確認してみましょう

var personA = {
  name: 'Bob',
  greeting: function() {
    alert('Hi! I\'m ' + name + '.');
  }
}

この状態でpersonA.greeting()を見てみると、アラートにはHi! I'm .と表示されます。
つまり、Bobという名前が引き継がれていないことがわかります。
それはなぜかというと、thisがないとグローバル変数を参照してしまうからです。

もう少しわかりやすく書きます。

var name = 'Sam';
var personA = {
  name: 'Bob',
  greeting: function() {
    alert('Hi! I\'m ' + name + '.');
  }
}

この状態で再度personA.greeting()を見てみます。
すると、アラートがHi! I'm Sam.となるのが確認できたでしょうか。

つまりthisを使わないとpersonA内のnameではなく、その外側の全体に対して定義されているnameが表示されてしまうということです。

もう少しわかりやすく言うと、thisは今のスコープのオブジェクト自体を指します。

今回はpersonAというスコープ内のnameを使いたかったので、thisが必要だったということですね。
そこまでわかると、以下のコードでなぜthisが入っていたかもわかるのではないでしょうか。

function Person(name) {
  this.name = name;
  this.greeting = function() {
    alert('Hi! I\'m ' + this.name + '.');
  };
}

let personA = new Person('Bob');
let personB = new Person('Sarah');

Allow関数を理解する

thisについてもう少し深堀りするついでに、Allow関数に関しても解説をしたいと思います。

まずはこちらのコードを見てください。

var name = 'Sam';
var personA = {
  name: 'Bob',
  greeting: function() {
    console.log('Hi! I\'m ' + this.name + '.');
  },
  IntervalGreeting: function() {
    setInterval(this.greeting, 1000)
  }
}

アラートだと見てて鬱陶しいのでconsole.log()に変えました。これで1000ミリ秒ごとにコンソール上では繰り返しHi! I'm 〇〇.と出力されるようになります。

*setInterval()というのはデフォルトで設定されている関数でsetInterval(関数名, 指定のミリ秒)と書くことで、指定したミリ秒ごとに関数が繰り返されるというものです。

そこでpersonA.IntervalGreeting()を実行して見ると、うまく表示されないのがわかるでしょうか。
Hi! I'm Sam.となってしまい、nameの部分がグローバル関数であるSamになってしまっていることがわかります。ただ、personA.nameだと正しくnameはBobになっていますよね。

この違いは何でしょうか。

そこで重要になるのが、thisは今のスコープのオブジェクト自体を指すということです。
personA.nameの場合、今のスコープのオブジェクトは当然personAになりますよね。
ただ、personA.IntervalGreeting()内のthis.greetingが表す今のスコープのオブジェクトはIntervalGreetingということになります。

このままでは少しわかりにくいかもしれませんが、setInterval()部分は以下のようにも書けるということを考えるとわかりやすいのではないでしょうか。

var personA = {
  name: 'Bob',
  greeting: function() {
    console.log('Hi! I\'m ' + this.name + '.');
  },
  IntervalGreeting: function() {
    setInterval(
      function() {
        console.log('Hi! I\'m ' + this.name + '.');
      }, 1000
    )
  }
}

つまり、関数の中に関数が入っている入れ子状態なので、一番内側となる入れ子の中でthisをしたところで何を取得すれば良いのか、このコードでは判断がつかないということですね。

それではどうすれば良いのかというと、Allow関数を使えば解決します。
Allow関数を使う場合、このように書きます。

() => {}

そしてAllow関数はthisを持ちません。つまり、**Allow関数を使った場合、一つ外側にthisを探しにいく(普通にスコープチェーンを辿る)**ということです。

なので、今回は下記のように書けば問題は解決します。

var name = 'Sam';
var personA = {
  name: 'Bob',
  greeting: function() {
    console.log('Hi! I\'m ' + this.name + '.');
  },
  IntervalGreeting: function() {
    setInterval(() => { this.greeting() }, 1000)
  }
}

再度personA.IntervalGreeting()を実行してみると、グローバルで指定しているnameのSamではなく、正しくHi! I'm Bob.と表示されることがわかりますね。

まとめ

以上のことをまとめると以下のことになります。

  • thisはオブジェクトを指すが、どのオブジェクトを指すかはどこで関数が呼ばれるかによって決定する
  • Allow関数は自身でthisを持たない

Allow関数に関しては毎回使うべきというわけではなく、メソッドでない場合には最適の方法になります。(メソッドでは使わない方がいい場合が多い)

まだ少し混乱があるかもしれませんが、もし迷ったら、とりあえずconsole.log()でログを出力してみるということも重要な方法になるので、実践しつつ感覚を掴んでいってもらえればよいかと思います。

もしもっと学びたいという方はぜひJavaScript道場にご参加ください。
次回はcanvasを使って背景やモンスターを描画する方法を書いていきます。

それでは最後までお読みいただきありがとうございました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?