JavaScript の getter/setter について
JavaScript で getter/setter が使えるということを今更ながら知った。同じ ECMAScript ベースの ActionScript は使えるのになー、と思ってたら案の定使えた。はい。私の不勉強でした。。。
参考:
- いろんな言語のSetter・Getterを比較してみた at HouseTect, JavaScriptな情報をあなたに
- IE 以外の JavaScript で getter setter が使えるようになる! - IT戦記
しかし、ほとんど使ってるのを見たことがない。いろんなライブラリでは速度が重視されるからか?とも思ったが、ライブラリだからこそ、こういうアクセッサメソッドは重要なんじゃないだろうか。
IEでは非サポートなので意味ないということかもしれないが。。(が、一応対応策はある)
とりあえず、どれくらい遅いのか測ってみることにした。
こんなオブジェクトを作って、直接アクセス、getter/setter アクセスの実行時間を比べてみた。
var Test = { a: 10, _num: 1, _str: 'hoge', _obj: {i: 1}, get num() { return this._num; }, set num(n) { this._num = n; }, get str() { return this._str; }, set str(s) { this._str = s; }, get obj() {return this._obj; }, set obj(o) { this._obj = o; }, };
なお、計測はこんな感じ。
function calcTime(count, fn){ var d = new Date().getTime(); for(var i=0; i<count; i++){ fn(); } var pd = new Date().getTime(); return (pd - d); } function start(){ var aGetTime = calcTime(count, function(){ var a = Test.a; }); var aSetTime = calcTime(count, function(){ Test.a = 100; }); ・・・
なぜか FireFox(3.6.13)では動かず。。。
Safari 5.0.3 と Chrome 9.0 で試しました。ループ回数は10000回で、何回か回した平均的な時間(ms)です。
項目 | Safari | Chrome |
Test.a get | 38 | 71 |
Test.a set | 35 | 70 |
Test.num get | 47 | 145 |
Test.num set | 53 | 149 |
Test.str get | 47 | 145 |
Test.str set | 54 | 150 |
Test.obj.i get | 47 | 147 |
Test.obj.i set | 64 | 158 |
Safari はやっ!!プロパティアクセスとメソッド呼び出しはほとんど違いありません。Chromeのほうは、大体倍くらいになってますね。しかしまあ、10万回アクセスでこんなものなので通常はほとんど誤差ですね。
というわけで、積極的に使っていこうと思います。
なお、当方の環境は MacBook Air11"(OS X 10.6.6) です。
まあ、しかし毎回打つのはめんどくさいので、Objective-C の @synthesize とかみたいにできないかな、と思って作ってみた。ruby のあれですね。
function attr_accessor(obj, name, initialValue){ var pname = "_" + name; obj.prototype[pname] = typeof initialValue === 'undefined' ? null : initialValue; obj.prototype.__defineGetter__(name, function() { return this[pname]; } ); obj.prototype.__defineSetter__(name, function(val) { this[pname] = val; } ); }; // 使い方 TestObj = function(){ }; // オブジェクトにプロパティとGetter/Setter、初期値を付ける。 attr_accessor(TestObj, 'foo', 'Hello Accessor!'); var o = new TestObj(); alert('o.foo: ' + o.foo);
これでプロパティもばっちり隠蔽! o._foo とかでアクセスできちゃうけど、まあないよりいいだろ。
しかし、作って思ったが、あんまり意味ないな。微妙。。。