タイトル長っ!というのは置いといて。
最近ちょこちょことJavaScriptをいじりはじめたのですが、thisの挙動に戸惑ったのでメモ。
次のコードは直感的に動いてくれる。
var kyube = { face: "(◕‿‿◕)" }; kyube.say = function () { document.writeln(this.face + "<僕と契約して魔法少女になってよ!"); }; kyube.say(); // (◕‿‿◕)<僕と契約して魔法少女になってよ!
次のコードは直感的に動いてくれない…。
var kyube = { face: "(◕ ‿‿ ◕)" }; kyube.say = function () { var helper = function () { document.writeln(this.face + "<僕と契約して魔法少女になってよ!"); }; helper(); }; kyube.say(); // undefined<僕と契約して魔法少女になってよ!
原因はhelper関数内のthisにグローバルオブジェクトがセットされているから。
JavaScript には関数の呼び出し方法が4つあって、それぞれthisにセットされるオブジェクトが違う。
簡単にまとめると、以下の通りになる。
メソッド呼び出し
関数がオブジェクトのメソッド(プロパティ)。
thisにはそのメソッドを持つオブジェクトが格納される。
関数呼び出し
関数がオブジェクトのメソッド(プロパティ)ではない(強いて言えばグローバルオブジェクトのプロパティ?)。
これはthisにグローバルオブジェクトがセットされる。
下のコードのhelperはこれ。
コンストラクタ呼び出し
関数をnewで呼び出した場合。
thisには新たに生成するオブジェクトが格納される。
apply呼び出し
関数をapply()で呼び出した場合。
thisは自由に指定できる(引数で指定可能)。
helperはオブジェクトのメソッド(プロパティ)ではないので、thisにはグローバルオブジェクトがセットされる。
いやいやそこにはkyubeセットされてろよ……というのが今回の話ですた。
対策としては、
var kyube = { face: "(◕ ‿‿ ◕)" }; kyube.say = function () { var that = this; var helper = function () { document.writeln(that.face + "<僕と契約して魔法少女になってよ!"); }; helper(); // (◕ ‿‿ ◕)<僕と契約して魔法少女になってよ! }; kyube.say();
とthatにオブジェクトをセットしておいて、それを利用する。