thisの遅延束縛 - JavaScriptの個人的なメモ (その3)
このメモについて
他の言語とJavaScriptの違いに関する個人的なメモですので、誤りがあるかもしれません。見つけたらご指摘ください。
前回のメモ - JavaScriptの多重継承とオーバライド - JavaScriptの個人的なメモ (その2)
http://d.hatena.ne.jp/dhrname/20121004
今回はthisを解説します。
this
JavaScriptにおいて、thisは参照しているオブジェクト自身のこととは限りません。
というのは、関数が呼び出される前には、thisに何が入っているのか不明です。関数が呼び出されるときに、その値を初めて決定します。
ためしに、nプロパティに数値の12を入れてみましょう。
var f = function(){ this.n = 12; }, obj = { hoge : f }; /*関数呼び出しパターン ( this = グローバルオブジェクト )*/ f(); window.n; /* 12 */ /*apply (call) 呼び出しパターン (this = 第1引数)*/ var s = {}; f.apply(s); f.call(s); s.n; /* 12 */ /*メソッド呼び出しパターン ( this = その場で呼び出したオブジェクト)*/ obj.hoge(); obj.n; /* 12 */ /*即時関数 ( this = グローバルオブジェクト )*/ (function(){ this; /* グローバルオブジェクト */ })(); /*コンストラクタ呼び出しパターン (returnを指定していなければ、this = 返り値)*/ s = new f(); s.n; /* 12 */ /*メソッドの参照引渡し つまり、メソッド呼び出しパターン*/ s.hoge = obj.hoge; s.n = 0; s.hoge(); /* this = s, this != obj */ s.n; /* 12 */ s = obj.hoge; s(); window.n; /* 12 だが、注意点として、IE8以前だけは、obj.n が12となる。IE9では修正*/ this; /* グローバルオブジェクト */
なお、このコードで使われているwindowオブジェクトが必ずしもグローバルオブジェクトとは限りません。これはブラウザの独自実装であることにご注意ください。
上のコードのとおり、メソッドの参照引渡しで問題が起こるのはthisのためです。
thisの性質を使えば、こんなこともできます。
document.id = function (id) { return this.getElementById(id); }; document.id("s"); /* メソッド呼び出しパターンなので、this = document */
結論
- thisは、値が流動的なので注意
- 関数呼び出しパターンはthisがグローバルオブジェクトになるので、特に注意