LoginSignup
1
1

More than 1 year has passed since last update.

【javascript】コールバック関数とthis

Last updated at Posted at 2021-11-22

case

クラスで定義されたメソッドをsetTimeoutから呼び出したときのthisの取り扱いについて。

  • Personクラスにhelloメソッドが定義されている。
  • Personクラスをインスタンス化してbob変数に代入している。
  • 変数bobをsetTimeoutで1秒後に実行するようになる。
  • 期待値としては、hello Bobと出力したいがhelloだけ出力されてしまう。

class Person {
  constructor(name, age) {
      this.name = name;
      this.age = age;
  }
  hello() {
     console.log('hello ' + this.name);
  }
}

const bob = new Person('Bob', 23);
setTimeout(bob.hello, 1000);

//実行結果
>>> hello

結論

bob.helloはPersonオブジェクトのhello()関数だけを実行していて、hello()メソッドにはPersonオブジェクトが渡されていないため、Bobにあたるthis.nameが
実行されない。

なぜか?

前提:javascriptの仕様なので受け入れるしかない。

  • 関数として実行されるthisはwindowオブジェクトを参照先となる。
  • 例としてwindowオブジェクトにnameプロパティを追加して"stan"を代入してみる。
  • するとhello stanと表示された。すなわちthisはwindowオブジェクトを参照している。

//例としてwindowオブジェクトにnameプロパティを追加して"stan"を代入してみる。
window.name = "stan"

class Person {
  constructor(name, age) {
      this.name = name;
      this.age = age;
  }
  hello() {
     console.log('hello ' + this.name);
  }
}

const bob = new Person('Bob', 23);
setTimeout(bob.hello, 1000);

//hello stanと表示された。すなわちthisはwindowオブジェクトを参照している。
>>> hello stan
  • これはsetTimeoutでbob.helloと実行した時にPersonオブジェクトのhelloを参照しているわけではない。
  • javascriptは、メモリ空間でPersonのhello()関数をコピーして、コピーをしたhello()関数を参照しているため、Personオブジェクトのプロパティを受け取れていないために起こる。
  • メモリ消費効率を考えた上の仕様なのでしょう。
  • そのため、Personオブジェクトを格納しているbob変数を束縛する必要がある。
どのように?
  • bind関数を使用する。
  • bind関数にbobオブジェクトを渡すとPersonオブジェクトを束縛することができる。

window.name = "stan"
class Person {
  constructor(name, age) {
      this.name = name;
      this.age = age;
  }
  hello() {
     console.log('hello ' + this.name);
  }
}

const bob = new Person('Bob', 23);
setTimeout(bob.hello.bind(bob), 1000);

>>> hello bob

ややこしいが、こういうものだと、受け入れる。

1
1
15

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
1