Crockfordの例に従って、Javascript (Chrome) で古典的な継承を使用しています。私は寄生インターフェースが好きですが、継承をカプセル化するためのもう少しクリーンな方法を探しています。
私が満たそうとしている追加の要件がいくつかあります。
- 親クラスのメソッドを、親メソッドを呼び出すことができる子クラスのメソッドでオーバーライドできるようにしたい
- 子クラスで親クラスのプロパティを再宣言する必要はありません。
これは、継承をカプセル化して利用しようとParasite
するメソッドを持つ私の親クラスです。extend
Object.defineProperty
function Parasite(host) {
var self = {};
self.host = host;
self.swollen = false;
self.init = function() {
console.debug('Parasite.init');
return self;
};
self.suck = function() {
console.log("I'm a parasite who sucks on " + self.host);
self.swollen = true;
return self;
};
self.extend = function(child) {
for(var prop in self) {
if (prop == 'extend') { // skip extend
console.debug('skip extend');
continue;
}
var is_extended = child.hasOwnProperty(prop);
var is_accessor = typeof self[prop] != "function";
// inherit prop
if (! is_extended) {
child[prop] = self[prop];
console.debug('prop', prop, 'inherited by child');
}
// default: override
else {
console.debug('prop', prop, 'overridden by child');
}
// For accessors, parent should reference child. This tries to
// synchronize them on the child's accesor.
if (is_accessor) {
var accessor = prop.toString();
console.warn('define accessor for', accessor, ':', child[accessor]);
Object.defineProperty(self, accessor, {
get: function() {
var val = child[accessor];
console.debug('getting', accessor, val, 'from', child, 'for', self);
return val;
},
set: function(val) {
console.debug('setting', accessor, val, 'from', child, 'for', self);
child[accessor] = val;
},
enumerable: true,
configurable: true
});
};
}
child.parent = self;
return child;
};
self = self.init();
return self;
}
これは私の子クラスですTick
:
function Tick(host) {
var self = {};
self.suck = function() {
self.parent.suck.call();
self.engorge();
};
self.engorge = function() {
console.log("And now I'm engorged with blood.");
};
self.init = function() {
var parent = new Parasite(host);
self = parent.extend(self);
return self;
};
self = self.init();
return self;
}
ここで私の最新のフィドルを見つけることができます (警告: Firefox では無限に再帰しますが、Chrome ではそうではありません):
コンソール出力は、アクセサーの問題が発生している場所を示しています。