3

拥有父

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 框架进行前端开发,一切都可以正常工作,但现在我也很想了解继承原型是如何工作的。

笔记! 我阅读了很多关于这个主题的文章,我知道有很多实现功能的“插件” 。不是我需要的。请回答问题,而不仅仅是链接有关该主题的文章(除非回答了该问题)。

谢谢!

4

5 回答 5

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所示。

于 2013-05-28T06:48:42.140 回答
3

我最近写了一篇文章,解释了为什么原型继承很重要。它有点长,但非常值得一读。

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

  1. 在第一种情况下,您使用的是delegate
  2. 在第二种情况下,您使用的是concatenation

我链接到你的帖子解释了真正的原型继承(即使用原型模式的原型继承)。

如果您在 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/

于 2013-05-28T06:51:09.710 回答
1

不,它们不一样。

Lion 原型的第一个示例成为Animal的实例。该实例确实继承自 Animal 原型,并将链接回该原型。如果修改了 Animal 原型,则实例将受到影响。

第二个示例只是简单地从 Animal 原型复制属性,Lion不会链接到实际的 Animal 原型本身。

于 2013-05-28T06:51:24.650 回答
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();
于 2013-11-20T15:32:53.063 回答
0

正如其他人已经提到的那样,是的,这是有区别的。

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

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

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

  • 对 Animal 的更改可能会波及并破坏 Lion 及其后代。委托原型的这种动态变化属性通常被认为是一件好事,但是当它应用于多级继承时,它经常会出现问题。

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

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

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

lion = Object.create(animal);

更好的是,把它放在工厂函数中:

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

与构造函数相比,工厂函数有很多优势,我不会在这里讨论。您可以在我对这篇文章的回答中看到更多详细信息:构造函数与工厂函数

于 2013-08-09T20:52:39.690 回答