Kawanet Blog III

川崎有亮(かわさきゆうすけ)のブログです。はてなに引っ越してきました。

JavaScript プロパティ lazy build 遅延初期化 getter メソッド

Haragayato (CC BY-SA 3.0)JavaScript で getter メソッド経由でプロパティの値を lazy build(lazy initialization/遅延初期化)する方法について。

handlebars とかのテンプレートエンジンに渡すオブジェクトで、テンプレート側で使う場合のみ必要に応じて lazy build したかった。予め getter を作っておけば、プロパティとしてテンプレートからアクセスできる。

 

var seq = 0;
var Foo = function () {
    this.seq = ++ seq;
};
var Bar = function () {
    this.fooB = new Foo();
};
Bar.prototype = {
    fooA: new Foo(), // shared
    get fooC() {
        return this._fooC = this._fooC || new Foo(); // lazy build
    }
};

var bar1 = new Bar();
var bar2 = new Bar();
var bar3 = new Bar();

console.log('bar1', bar1.fooA.seq, bar1.fooB.seq, bar1.fooC.seq); // 1 2 5
console.log('bar3', bar3.fooA.seq, bar3.fooB.seq, bar3.fooC.seq); // 1 4 6
console.log('bar2', bar2.fooA.seq, bar2.fooB.seq, bar2.fooC.seq); // 1 3 7

 

Foo の seq プロパティは、Foo インスタンスを生成したシリアル番号。
Bar の fooA・fooB・fooC プロパティは、いずれも Foo のインスタンスを持つ。

 

(prototype にインスタンスを持たせる場合)

fooA プロパティは、Bar.prototype 定義時に Foo インスタンスができていて、
全ての Bar インスタンスで共有されるので、bar1/bar2/bar3 いずれも 1 となる。

 

(通常のプロパティ値にインスタンスを持たせる場合)

fooB プロパティは、Bar インスタンス作成時に Foo インスタンスができるので、
Bar インスタンスの生成順から、bar1=2→bar3=4→bar2=3 という結果になる。

 

(プロパティ値を lazy build する場合)※今回の主旨

fooC プロパティは、fooB プロパティを呼び出した際に Foo インスタンスができるので、
fooC プロパティのアクセス順から、bar1=5→bar3=6→bar2=7 という結果になる。
実際の Foo インスタンスは _fooC というプライベート風味プロパティに置いた。

 

get fooC() のゲッター定義が使えない古い環境では以下を使う。

Bar.prototype.__defineGetter__('fooC', function(){
    return this._foo = this._foo || new Foo();
});

 

(参考記事)
http://news.mynavi.jp/articles/2010/09/09/ie9-ie8-getter-setter-javascript/index.html
http://d.hatena.ne.jp/amachang/20090115/1231989477
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineGetter

 

サンクス!>@mitsumitsu123 

CC BY-SA 3.0 の 下駄 は Haragayato さん。