Javascriptでのオブジェクト定義方法として、prototypeチェーンを使うのが一般的。
多少の変形があるが、おおよそは下記のような構造での継承の仕組みをCoffeeScriptのようなトランスレータやPrototype.js, jQueryのようなフレームワークなどでも使用している
(CoffeeScriptなどでは直接規定オブジェクトのインスタンスを生成せず、継承の実現方法にいわゆる「extend」関数を使っているはず)
- コンストラクタ関数を定義
- 継承にて基底オブジェクトとして使用する場合、引数0個でのオブジェクト生成できるようにするのがよさそう
- ECMAScript 5th対応であれば、Object.create(MyObject.prorotype)でもよい。
- (派生オブジェクトを作る場合)
- prototypeプロパティに基底オブジェクトのインスタンスを作成し、設定する。
- prototype.constructorプロパティにコンストラクタ関数を設定する。
- prototypeプロパティにインスタンスメソッドとして関数オブジェクトを追加する
CoffeeScriptなどでは対処されているが、下記のような手動での継承方法では
-
staticメソッド相当の関数を派生オブジェクト側で取り込んでいない
- `MyObject.static_methodをMyObjectDerived.static_methodとしてcallできない
-
継承を実現するための仕組みをコードを書く側が常に意識して記述しないといけない
- コンストラクタ関数のarguments.length == 0の場合の特別扱い
- 派生オブジェクト側での__chain__変数定義、
- 派生オブジェクト側でのprototype.constructorの復元
plain_old_derived.js
var MyObject = (function() {
function MyObject(aName){
this.name = "";
if (arguments.length > 0) {
this.name = aName;
}
}
MyObject.prototype.sayHello = function () {
alert("Hello! " + this.name);
}
return MyObject;
})();
var MyObjectDerived = (function() {
function MyObjectDerived(aName, aNumber){
this.name = "";
this.number = 0;
if (arguments.length > 0) {
this.name = aName;
this.number = aNumber;
}
}
// 「extend」関数相当
var __chain__ = MyObject.prototype;
MyObjectDerived.prototype = new MyObject;
MyObjectDerived.prototype.constructor = MyObjectDerived;
MyObjectDerived.prototype.sayHello = function () {
__chain__.sayHello.call(this);
for (var index = 0, length = this.number; index < length; ++index) {
alert("Goodbye! " + this.name);
}
}
return MyObjectDerived;
})();
var o1 = new MyObject("name 1");
o1.sayHello();
var o2 = new MyObjectDerived("name 2", 1);
o2.sayHello();