basyura's blog

あしたになったらほんきだす。

this と global と function

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

設計ミスの結果、あるオブジェクトのメソッドにおいて、処理の一部を内部関数に担当させる、といったことができなくなった。なぜなら、呼び出された内部関数では、this に間違った値が設定されてしまっており、呼び出し元のメソッドと、thisオブジェクトくを共有できないからだ。
- p.33 4.3.2 関数呼び出しパターン -

一度読んだだけではよく分からなかったけど、以下のコードを書いて理解。内部関数内で this は global な this になってしまう(設計ミスの結果)。通例で that という名前の変数を定義して this を突っ込む。that 経由でアクセスすると内部変数にアクセスすることができる。

// グローバルな値
var value = "999";
var myObject = {
	value: 0, // 内部変数
	increment: function(inc) {
		this.value += typeof inc === 'number' ? inc : 1;
	},
	add: function(a,b) {
		return a + b;
	}
}
myObject.double = function() {
	var that = this;
	// myObject の変数が参照される
	print("this.value@double is " + this.value); //=> 3
	print("that.value@double is " + that.value); //=> 3
	var helper = function() {
		// that を経由することでmyObject 内の add にアクセスできる。
		that.value = that.add(that.value , that.value);
		// ここでの this は global なのでトップレベルの変数が参照される
		print("this.value@helper@double is " + this.value); //=> 999
		// that を経由すると myObject 内の変数を参照できる。
		print("that.value@helper@double is " + that.value); //=> 6
	};
	helper();
};
myObject.increment();
myObject.increment(2);
myObject.double();
print("this.value@global is " + this.value); //=> 999

仕様は分かったけど、なんで that 経由なら OK なのかが良く分からない・・・。
内部関数から this.hoge にアクセスする場合は関数も this.func と定義しないとダメなんだと思っていたけど、これは激しく勘違だったってことが分かった orz