我知道Javascript没有类,也不支持经典的面向对象编程继承。但是我发现这种模式非常有用,所以我想构建一种简单的方式来模拟这种行为,同时最好能够利用Javascript灵活性的最佳部分。以下方法的优缺点是什么?
我在我的自定义库中有以下函数:
function inherit(superClass, args, instance) {
var subClass = inherit.caller;
var o = new superClass(args);
for(p in o) {
if(o.hasOwnProperty(p)) init(instance, p, o[p]);
else init(subClass.prototype, p, o[p]);
}
}
function isUndefined(x) {var u; return x === u;}
// sets p to value only if o[p] is undefined
function init(o, p, value) {if(isUndefined(o[p])) o[p] = value;}
这个设置需要遵循两种约定:
- 模拟类的函数必须接收一个参数:一个具有命名属性的对象。
- 希望从其他函数“继承”的函数必须调用inherit函数。
以下是结果示例(将其与库函数一起粘贴到Firebug命令行中,以查看它的实际效果):
function SuperClass(args) {
this.x = args.x;
}
SuperClass.prototype.p = 'SuperClass prototype property p';
function SubClass(args) {
inherit(SuperClass, args, this);
this.y = args.y;
}
SubClass.prototype.q = 'SubClass prototype property q';
var o = new SubClass({
x: 'x set in SuperClass',
y: 'y set in SubClass'
});
console.dir(o); // correctly has properties x, y, p, and q
['x', 'y', 'p', 'q'].forEach(function(prop) {
// true for x and y, false for p and q
console.log("o.hasOwnProperty('" + prop + "')", o.hasOwnProperty(prop));
});
console.log("o instanceof SubClass: ", o instanceof SubClass); // true
console.log("o instanceof SuperClass: ", o instanceof SuperClass); // false
我知道以下不足之处:
- 修改超类原型不会影响您的实例对象,这可能与原型式继承的预期不同
- 实例对象将不注册为超类的实例(尽管它仍然像一个)
- 参数约定可能很烦人
- 只需要一个函数调用(易于实现)
- 区分原型属性和实例属性
- 传递给子类的参数也传递给超类
- 由超类构造函数设置的实例属性立即在子类构造函数中可用
- 多重继承很容易,在子类中多次调用inherit即可
- 不会覆盖子类的现有属性
SubClass.prototype = new SuperClass()
方法。其他方法,例如dojo的类建模,更加复杂,我认为这是没有必要的。所以,请告诉我您的想法。如果其他人已经做过这件事,请告诉我,我没有意图复制任何想法。
caller
是非标准的,在严格模式 ES5 中访问它将会抛出错误。 - Christoph