【发布时间】:2011-05-04 13:21:13
【问题描述】:
我意识到 Javascript 没有类,也不是为了具有经典的 OOP 继承而构建的。但我发现这样的模式非常有用,因此我想构建一种简单的方法来模拟这种行为,理想情况下,同时利用 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;}
此设置需要两个约定:
- 作为建模类的函数必须采用一个参数:具有命名属性的对象
- 希望从另一个“继承”的函数必须调用继承函数。
这是您得到的结果示例(粘贴到 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
- 不会覆盖子类的现有属性
优点 3 - 6 使这种方法对我来说比 SubClass.prototype = new SuperClass() 方法更有用。其他方法,比如 dojo 的类建模,要复杂得多,我认为没有必要。
所以,告诉我你的想法。如果其他人以前这样做过,请告诉我,我无意重复任何想法。
【问题讨论】:
-
请记住
caller是非标准的,在严格模式的 ES5 中访问它会引发错误 -
到目前为止我最喜欢的解决方案是coffeescript! jashkenas.github.com/coffee-script
标签: javascript oop inheritance prototype-programming