JavaScript中继承模型的优缺点是什么?

9

我知道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;}

这个设置需要遵循两种约定:

  1. 模拟类的函数必须接收一个参数:一个具有命名属性的对象。
  2. 希望从其他函数“继承”的函数必须调用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

我知道以下不足之处:
  1. 修改超类原型不会影响您的实例对象,这可能与原型式继承的预期不同
  2. 实例对象将不注册为超类的实例(尽管它仍然像一个)
  3. 参数约定可能很烦人
好处如下:
  1. 只需要一个函数调用(易于实现)
  2. 区分原型属性和实例属性
  3. 传递给子类的参数也传递给超类
  4. 由超类构造函数设置的实例属性立即在子类构造函数中可用
  5. 多重继承很容易,在子类中多次调用inherit即可
  6. 不会覆盖子类的现有属性
其中好处3至6使我更喜欢这种方法而非SubClass.prototype = new SuperClass()方法。其他方法,例如dojo的类建模,更加复杂,我认为这是没有必要的。
所以,请告诉我您的想法。如果其他人已经做过这件事,请告诉我,我没有意图复制任何想法。

2
请注意,caller 是非标准的,在严格模式 ES5 中访问它将会抛出错误。 - Christoph
到目前为止,我最喜欢的解决方案是Coffeescript!http://jashkenas.github.com/coffee-script/ - Chris
3个回答

4

以下是一个简单且可能是JavaScript中实现继承最佳方法,如果您希望了解,请阅读以下内容,它比我浏览过的其他所有方法都要简单得多:

http://javascript.crockford.com/prototypal.html

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

注意:在较新的浏览器中,Object.create已成为JavaScript的一部分,但通过添加上述代码,以下内容也适用于旧版浏览器。

newObject = Object.create(oldObject);

3

0

你知道你发布的内容的缺点...所以请看看我的博客,其中详细解释了我认为最好的方法,同时描述了其他模式的缺陷。

http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

例子:

//Abstraxct base class
function Animal(name) {
  this.name = name;
}

Animal.prototype.sayMyName = function () {
  console.log(this.getWordsToSay() + " " + this.name);
}

Animal.prototype.getWordsToSay = function () {} // abstract

// --------------------------------

function Dog(name) {
  // Call the parent's constructor
  Animal.call(this, name);
}

extend(Dog, Animal, {
  getWordsToSay: function(){
    return "Ruff Ruff";
  }
});

我发布的代码是一个语法示例。博客文章详细介绍了如何添加语法糖。
重要的事情是:
  • new Dog("Lassie") instanceof Animal // true
  • Animal构造函数不仅用于设置继承
  • var dog = new Dog("Lassie"); Animal.prototype.blah = 5; dog.blah == 5; //输出为true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接