JavaScript でオブジェクトを継承してみる

最近 __proto__ プロパティを使うとオブジェクトの継承ができることを知った。

シンプルに書くとこんな感じ。ちなみにサンプルコードは Rhino で実行・確認しました。printが使えない環境ではalertなどに置き換えてね。

var a = {};
a.v = "abcd";
a.f = function() { return this.v; };

var b = {};
b.__proto__ = a; // a オブジェクトを継承

print( b.f() ); // 親オブジェクト a の f() が呼ばれる

実行結果

abcd


これを応用してコンストラクタ(っぽい関数)を呼び出してオブジェクトのインスタンスをつくる方法を思いついた。継承できるし、メソッドオーバーライトもできるよ。

こんな感じ。

var createA = function(n) {
        // private
        var v = n;

        // public
        var _public = {};
        // _public.__proto__ = Object.prototype; // Object.prototype を参照
        _public.f = function() { return v * 10; };
        _public.g = function() { return v * 100; };
        return _public;
};
var createB = function(n) {
        // public
        var _public = {};
        _public.__proto__ = createA(n); // A オブジェクトを継承
        _public.g = function() { return _public.__proto__.g() * 2; }; // g メソッドをオーバーライド
        return _public;
};

var a = createA(1); // A オブジェクトのインスタンス a を生成
var b = createB(1); // B オブジェクトのインスタンス b を生成

print( a.f() );
print( a.g() );
print( b.f() );
print( b.g() );

実行結果

10
100
10
200


前から new 演算子と prototype プロパティを使って似たようなことができるのは知ってたけど直感的じゃないので使いたくなかったんだよね。

var A = function(n) {
        this.v = n;
};
A.prototype.f = function() { return this.v + this.v; };

var B = function(n) {
        this.v = n
};
B.prototype = new A(); // A オブジェクトを継承 (new A()ってなに?きもっ)
var b = new B(1);
print( b.f() );
print(b instanceof B); // B オブジェクトのインスタンスか判別
print(b instanceof A); // A オブジェクトを親に持つインスタンスか判別

実行結果

2
true
true


__proto__を使えば new や prototype を使わず直感的に記述できてうれしい(おいらは)。instanceof でオブジェクトの継承関係を判別できないのは残念だけど。。(ひょっとして、できる?)