基本的な継承に関わる機能を提供します。
- APIリファレンス: at.pkgs.Object
使用例
基底クラスのメソッド呼び出し(正しい方法)
基底クラスのメソッドを呼び出すメソッドはインスタンス変数を伝播するように設計してください。
var A, B, C;
A = at.pkgs.Object.extend((
function(num, instance) {
instance = instance || this;
this.parent.self(instance);
console.log('A(' + num + ')');
instance.x = num;
}
), { /* prototype */
x: null,
f: function() {
console.log('A.x: ' + this.x);
}
}, { /* statics */
});
B = A.extend((
function(num, instance) {
instance = instance || this;
this.parent.self(num, instance);
console.log('B');
}
), { /* prototype */
}, { /* statics */
});
C = B.extend((
function(num, instance) {
instance = instance || this;
this.parent.self(num, instance);
console.log('C');
}
), { /* prototype */
}, { /* statics */
});
var c0, c1;
c0 = new C(0);
// A(0)
// B
// C
c1 = new C(1);
// A(1)
// B
// C
c0.f();
// A.x: 0
c1.f();
// A.x: 1
基底クラスのメソッド呼び出し: 誤った方法#1: 親クラスのプロトタイプ汚染
基底クラスへインスタンス変数を渡さないため親クラスのプロトタイプが汚染されます。
var A, B, C;
A = at.pkgs.Object.extend((
function(num) {
this.parent.self();
console.log('A(' + num + ')');
// !!!!!!!!!!
this.x = num;
}
), { /* prototype */
x: null,
f: function() {
console.log('A.x: ' + this.x);
}
}, { /* statics */
});
B = A.extend((
function(num) {
this.parent.self(num);
console.log('B');
}
), { /* prototype */
}, { /* statics */
});
C = B.extend((
function(num) {
this.parent.self(num);
console.log('C');
}
), { /* prototype */
}, { /* statics */
});
var c0, c1;
c0 = new C(0);
// A(0)
// B
// C
c1 = new C(1);
// A(1)
// B
// C
c0.f();
// !!!!!!
// A.x: 1
c1.f();
// A.x: 1
基底クラスのメソッド呼び出し: 誤った方法#2: 親クラスから親クラスのメソッドが呼び出せない
子孫の実行コンテキストで親クラスのメソッドを呼び出すと親クラスから親クラスを呼び出すことができません。
var A, B, C;
A = at.pkgs.Object.extend((
function(num) {
this.parent.self.call(this);
console.log('A(' + num + ')');
this.x = num;
}
), { /* prototype */
x: null,
f: function() {
console.log('A.x: ' + this.x);
}
}, { /* statics */
});
B = A.extend((
function(num) {
this.parent.self.call(this, num);
console.log('B');
}
), { /* prototype */
}, { /* statics */
});
C = B.extend((
function(num) {
this.parent.self.call(this, num);
console.log('C');
}
), { /* prototype */
}, { /* statics */
});
var c0;
c0 = new C(0);
// B
// B
// B
// B
// B
// ...
サブクラスに未実装のメソッドの多重呼び出しに対する備考
下記のようなケースを考慮してください。
var A, B, C;
A = at.pkgs.Object.extend((
function(instance) {
instance = instance || this;
this.parent.self(instance);
}
), { /* prototype */
initialize: function(instance) {
instance = instance || this;
console.log('A');
}
});
B = A.extend((
function(instance) {
instance = instance || this;
this.parent.self(instance);
}
), { /* prototype */
initialize: function(instance) {
instance = instance || this;
console.log('B:0');
this.parent.initialize(instance);
console.log('B:1');
if (!this.immediate('initialize')) return;
// ここは安全です
console.log('B:2');
}
});
C = at.pkgs.Object.extend((
function(instance) {
instance = instance || this;
this.parent.self(instance);
}
), { /* prototype */
// initializeをオーバーライドしません.
});
(new C()).initialize();
// B:0
// B:0
// A
// B:1
// B:2
// B:1
上記の例ではクラスCでinitialize()メソッドをオーバーライドしていないため、C#initialize()メソッド呼び出しでプロトタイプチェイン経由でB#initialize()が実行されます。 通常この振る舞いは意図しないものとなります。 at.pkgs.Object#immediate(name)等を使用して多重実行からガードしてください。