继承原型

时间:2013-05-28 06:11:20

标签: javascript

拥有父

function Animal() {
  // do something
}

Animal.prototype.walk = function() {
  alert('I am walking.');
};

和孩子

function Lion() {
  // do something
}

如果我希望Lion继承Animal的原型,通常的做法是:

Lion.prototype = new Animal();

// Set the constructor to Lion, because now it points to Animal
Lion.prototype.constructor = Lion;

这与此有什么不同(结果不是性能)?

$.extend(Lion.prototype, Animal.prototype);

对于非jquery开发人员:$.extend将所有原型方法和属性一个一个地从Animal复制到Lion。

我不是javascript中继承的大专家。我通常使用MVC框架进行前端开发,其中一切正常,但现在我也想了解继承原型是如何工作的。

注意! 我阅读了很多关于这个主题的文章,我知道有很多"plugins"实现了 Class 功能。这是我需要的东西。请回答这个问题,而不只是链接有关该主题的文章(除非有答案)。

谢谢!

5 个答案:

答案 0 :(得分:3)

有一点不同,在两个原型之间复制属性并不会使它们彼此“连接”,即:

$.extend(Lion.prototype, Animal.prototype);

// add one more method to the prototype
Animal.prototype.test = function() {
  alert('test');
};

var x = new Lion();
x.test(); // TypeError: Object <Lion> has no method 'test'

如果您使用new Animal()作为Lion的原型,那么您就不会这样做,如here所示。

答案 1 :(得分:3)

我最近写了一篇解释Why Prototypal Inheritance Matters的文章。这有点长,但值得一读。

要直接回答您的问题,是Lion.prototype = new Animal$.extend(Lion.prototype, Animal.prototype)不同,因为:

  1. 在第一种情况下,您使用的是delegation
  2. 在第二种情况下,您使用的是concatenation
  3. 我联系你的帖子解释了真正的原型继承(即使用原型模式的原型继承)。

    如果您在JavaScript中使用了真正的原型继承,那么这就是您的程序的样子:

    var animal = {
        create: function () {
            return this.extend();
        },
        walk: function () {
            alert("I am walking.");
        }
    };
    
    var lion = animal.extend({
        create: function () {
            return animal.create.call(this);
        }
    });
    

    此处extend函数是我链接到您的帖子中的函数。

    将此与您使用构造函数模式进行原型继承的代码进行对比。

    这是一个小提琴,展示了真正的原型继承:http://jsfiddle.net/6x4BU/

答案 2 :(得分:1)

不,他们不一样。

Lion原型的第一个例子成为Animal的实例。该实例继承自Animal原型并将链接回该原型。 如果动态原型被修改,实例将受到影响。

第二个例子只是从Animal原型中复制属性,而Lion 将不会链接到实际的Animal原型本身。

答案 3 :(得分:0)

正如其他人已经提到的那样,是的,存在差异。

在第一个示例中,对Animal原型的更改将更改Lion实例的行为。

在第二个示例中,Lion在$ .extend()调用时继承了Animal 的功能。

第一种方式有一些可能有害的副作用,特别是:

  • 对动物的改变会涟漪并打破狮子及其后代。委托原型的动态更改属性通常被认为是一件好事,但当它应用于多级继承时,它经常会导致问题。

  • 第一种方法不允许来自Animal的选择性继承。这是全有或全无。你想要香蕉,但你得到的是大猩猩,香蕉和整个丛林。 (这个着名的问题叫做大猩猩/香蕉问题)。后一种方法允许您选择性地继承Animal:$.extend(Lion.prototype, { run: Animal.prototype.run, sleep: Animal.prototype.sleep });

  • instanceof打破连接 - 但instanceof在任何情况下都不可靠。如果你重新分配动物原型,它将会破裂。如果您尝试在执行上下文中使用它,它会中断。换句话说,不使用instanceof ,无论您选择哪种继承方法。

根本不需要构造函数。您可以创建一个名为animal的对象文字并执行此操作:

lion = Object.create(animal);

更好的是,把它放在工厂功能中:

function lion(options) {
  return $.extend(Object.create(lion), options);
}

工厂函数比构造函数有很多优点,我不会在这里讨论。您可以在此帖子的回答中查看更多详细信息:Constructor function vs Factory functions

答案 4 :(得分:0)

这是纯JavaScript中的基本原型继承

// base class declaration
function Animal (arg) {
    this.arg = arg;
}

// just a method in the Animal class, it can be whatever you want
Animal.prototype.roar = function () {
    alert(this.arg);
};

// object that inherits the base class
function Lion (arg) {
    // the call to the super constructor
    Animal.call(this, arg);
}

// the prototypical inheritance
Lion.prototype = Object.create(Animal.prototype);
// the constructor needs to be set so that it does not show as the base constructor
// otherwise the constructor for all instances of Lion will show as Animal
Lion.prototype.constructor = Lion;

var symba = new Lion('the lion is roaring');

symba.roar();