Rubellum fly light

ほぼPHP日記

関数呼び出しでは、thisにはグローバルオブジェクトがセットされるという話

タイトル長っ!というのは置いといて。
最近ちょこちょこと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にオブジェクトをセットしておいて、それを利用する。