JavaScriptのオブジェクト指向プログラミングの履歴
なんでprivateなインスタンスメソッドの中でthis使えないの?
var A = function(){ var hoge = function(){ console.log(this, " in Private"); } this.moge = function(){ console.log(this, " in Privileged"); hoge(); } } var obj = new A(); obj.moge(); return;
実行すると
Object in Privileged Window test.html in Private
こうなりました。
あーそうか、関数呼ぶときは{object}.{method}にしないとだめなんだ。そうしないと暗黙的にグローバルオブジェクトwindowが使われるのか。
いやまて、どっちにしろオブジェクト「A」はメソッド「hoge」を持ってるわけなくて、存在しているのはコンストラクタのスコープの中だけか。
function(){} の中身は別のスコープになるんだけど、呼び出す側によって、コンテキスト(何がthisか)を変更できる。
hoge()
のように、オブジェクトを指定しなければ、どんな場所でもコンテキストにグローバルオブジェクトが使われ
obj.hoge()
とすると、objのコンテキストでhoge()が実行される。
スコープとコンテキスト混同してたわ。
こうすると使えるようになります。
var A = function(){ var hoge = function(){ console.log(this, " in Private"); } this.moge = function(){ console.log(this, " in Privileged"); hoge.call(this); } } var obj = new A(); obj.moge(); return;
Object in Privileged Object in Private
カプセル化まとめ
privateなメソッドの中でthisできないの知らなくてちょっとはまった…。call, applyで呼べるっちゃ呼べるけどどうなんだろ…。
privateメソッドっていうよりクロージャって呼んだ方がよくね?
// コンストラクタ var Human = function(name, called){ // private member // - このスコープでのみアクセス可能 var happy = false; // public member // - いつでもアクセス可能 this.name = name; // private method // - 単なるクロージャ // - 普通に呼び出すとグローバルコンテキストで実行される。 // callしない限りこのオブジェクトでのthisが使えない // - private memberのみアクセスできる var format = function(){ return name + ', "' + called + '"'; } // privileged method // - privateにもpublicにもアクセスできる this.makeHappy = function(){ happy = true; }; this.isHappy = function(){ return happy; } this.toString = function(){ return format(); } }; // public method // - privilegedにアクセスできる // - privileged が定義されていればそちらが優先させる Human.prototype.faith = function(num){ this.makeHappy(); }; var akkun = new Human('akkun', 'the sleeping drummer'); console.log(akkun.name); console.log(akkun.toString()); console.log(akkun.isHappy()); akkun.faith(); console.log(akkun.isHappy()); console.log(akkun.format);
出力
akkun akkun, "the sleeping drummer" false true undefined
privileged method はprivateにもpublicにもアクセスできるなら、publicいらなくない?
http://blogs.msdn.com/kristoffer/archive/2007/02/13/javascri...
prototypeで定義する方が速いです。
といっても差がでるのは万単位でnewする場合だけど。
privateやprivilegedにすると、newするたびに、関数の中が実行される。メソッドなども再定義される。
のでメモリを食う。生成に時間もかかる。
publicなインスタンス変数はprototypeで定義するのではない
インスタンスメソッドがprototypeで定義するんだったら、インスタンス変数もそうなんだろうと勝手に思い込んでこんなコードを書いた。
コード
var i = 0; var Hoge = function(){ this.myprop.push(i++); } Hoge.prototype.myprop = []; var hoge1 = new Hoge(); var hoge2 = new Hoge(); var hoge3 = new Hoge(); println(hoge1.myprop); println(hoge2.myprop); println(hoge3.myprop);
結果
0,1,2,3 0,1,2,3 0,1,2,3
おお、なんてこった。みごとに共有されている!
prototypeとは何かを理解していればこんなことにはならなかったかも…。自分自身に定義されてなければ、prototypeオブジェクトを参照する。
このコードの場合、自分にmypropが定義されていないので、prototypeの方を参照する。オブジェクト全てが同じprototypeのmypropを参照するのでこうなる。関数の場合は同じものを参照すればいいんだけど、変数は共通のものを使えない。結局コンストラクタ内でthisするしかない。
ちなみに、hasOwnPropertyしてみるとprototypeを使っているかどうかがわかる。