JavaScriptでタイマー処理をしたいものがある場合、関数setIntervalか関数setTimeoutを使う。ここでどちらかの関数から、任意のオブジェクトのメソッドを呼び出すと、メソッドの挙動が意図とは違ったものになることがある。原因を探るとメソッド内でthisを使っていて、このthisを使う上での勘違いが意図とは違う挙動をひき起こしていることがわかる。このthisに関して少し。
上のコードを実行すると、アラートウィンドウでundefinedが表示される。コードを書いたときの意図として、obj.fooの値である"foo"という文字列を表示したくて書いたとしても。このあたりはいろいろなところで語られているのを見た。解決策としていくつかあるが、そもそもこの意図と挙動の食い違いのもとになっているthisがなにを指すのか、JavaScriptにおいてオブジェクトのメソッドとはなんぞというところまで考えたのでメモしておく。
"this は関数に「渡される」のであって、関数に固定されている訳ではありません" 参考
ほうほう。ぼくはいままでメソッド内で使っていたthisが、メソッドを定義した時点で、そのメソッドを入れているオブジェクトで固定されるものだと思っていた。そうでないのなら、どっかで定義した任意の関数にthisを使っておいてメソッドとして呼び出しても意図通りに動いてくれる。
http://jsfiddle.net/hiroaki/p787c/
関数setTimeoutなどからメソッドを呼び出したときのthisが指すオブジェクトのうんぬんに関して、「thisが自分の元であるオブジェクトを指すわけではない」と表現しているブログ記事を読んでちょっと違和感があった。一方でさきほどリンクとして挙げたMozillaのページで以下のとおりに書いてあったのを読んでスッキリした。
"メソッドはそれをメソッドとして持つオブジェクトに束縛されているのではなく、オブジェクトによって参照されているだけです"
JavaScriptにおけるメソッドとは実はただの関数への参照である。オブジェクトと深く結びついてそのプロパティやメソッドにいつでも大した工夫もなくアクセスできるようになっている…わけではない。平時はthisを使うことで簡単にできるが、setTimeoutなど別オブジェクトからメソッドを使うときはthisが指すオブジェクトを意図通りにものにするため、コードに工夫を施さなければならない。JavaScriptにおいてメソッドと呼ばれているものは、実はそのメソッドを持つオブジェクトと厳密に結びついているものではなく、宙ぶらりんの関数への参照だ。
*厳密にはJavaScriptにメソッドはなく、あるのは関数への参照をも入れられるプロパティだというのをどこかのブログで読んだ気がするが、再び見つけることができなかった。
ぼくなりの解釈としては、JavaScriptでメソッドと呼ばれているものはオブジェクトという意味では自分を持っていない。だから自分の元を指すことはそもそもできない。メソッドの中では自分の属するオブジェクトを指そうとthisが使われるが、実際のthisはメソッドと思われているその関数が呼ばれた文脈によって指されるオブジェクトを判断する。
http://jsfiddle.net/s4W4T/2/
var obj = {}
obj.foo = "foo";
obj.func = function(){alert(this.foo);};
setTimeout(obj.func, 300);
上のコードを実行すると、アラートウィンドウでundefinedが表示される。コードを書いたときの意図として、obj.fooの値である"foo"という文字列を表示したくて書いたとしても。このあたりはいろいろなところで語られているのを見た。解決策としていくつかあるが、そもそもこの意図と挙動の食い違いのもとになっているthisがなにを指すのか、JavaScriptにおいてオブジェクトのメソッドとはなんぞというところまで考えたのでメモしておく。
"this は関数に「渡される」のであって、関数に固定されている訳ではありません" 参考
ほうほう。ぼくはいままでメソッド内で使っていたthisが、メソッドを定義した時点で、そのメソッドを入れているオブジェクトで固定されるものだと思っていた。そうでないのなら、どっかで定義した任意の関数にthisを使っておいてメソッドとして呼び出しても意図通りに動いてくれる。
function roar()
{
print(this.voice);
}
var hentai =
{
voice: "オロロロロロロ",
cry: roar,
}
roar();
hentai.cry();
http://jsfiddle.net/hiroaki/p787c/
関数setTimeoutなどからメソッドを呼び出したときのthisが指すオブジェクトのうんぬんに関して、「thisが自分の元であるオブジェクトを指すわけではない」と表現しているブログ記事を読んでちょっと違和感があった。一方でさきほどリンクとして挙げたMozillaのページで以下のとおりに書いてあったのを読んでスッキリした。
"メソッドはそれをメソッドとして持つオブジェクトに束縛されているのではなく、オブジェクトによって参照されているだけです"
JavaScriptにおけるメソッドとは実はただの関数への参照である。オブジェクトと深く結びついてそのプロパティやメソッドにいつでも大した工夫もなくアクセスできるようになっている…わけではない。平時はthisを使うことで簡単にできるが、setTimeoutなど別オブジェクトからメソッドを使うときはthisが指すオブジェクトを意図通りにものにするため、コードに工夫を施さなければならない。JavaScriptにおいてメソッドと呼ばれているものは、実はそのメソッドを持つオブジェクトと厳密に結びついているものではなく、宙ぶらりんの関数への参照だ。
*厳密にはJavaScriptにメソッドはなく、あるのは関数への参照をも入れられるプロパティだというのをどこかのブログで読んだ気がするが、再び見つけることができなかった。
ぼくなりの解釈としては、JavaScriptでメソッドと呼ばれているものはオブジェクトという意味では自分を持っていない。だから自分の元を指すことはそもそもできない。メソッドの中では自分の属するオブジェクトを指そうとthisが使われるが、実際のthisはメソッドと思われているその関数が呼ばれた文脈によって指されるオブジェクトを判断する。
http://jsfiddle.net/s4W4T/2/
スポンサーサイト