Prototype copy vs Object.create()vs new

use*_*212 5 javascript inheritance

我正在使用继承,我注意到有三种方法可以获得相同的结果.有什么不同?

function Animal(){
}

Animal.prototype.doThat = function() {
    document.write("Doing that");
}

function Bird(){
}

// This makes doThat() visible
Bird.prototype = Object.create(Animal.prototype); // Solution 1
// You can also do:
// Bird.prototype = new Animal(); // Solution 2
// Or:
// Bird.prototype = Animal.prototype; // Solution 3

var myVar = new Bird();
myVar.doThat();
Run Code Online (Sandbox Code Playgroud)

如你所见,我提出了三个解决方案.它们中的每一个都使方法doThat()可见.

如果我评论所有这些,确实存在错误.

如果我只解除其中一个程序的作用.

那么......三种解决方案之间真正区别的是什么?

Fel*_*ing 13

Bird.prototype = Animal.prototype; // Solution 3

由于这是Animal.prototype直接赋予的Bird.prototype,因此对后者所做的所有更改也将反映在Animal从中继承的所有其他类中.

例如:

Bird.prototype.fly = function() {
    console.log('I can fly.');
}

var some_animal = new Animal();
some_animal.fly(); // this will work
Run Code Online (Sandbox Code Playgroud)

这当然不是你想要的.此子类的每个方法不仅可用于其他子类,而且如果覆盖子类中的父方法,则最后定义的子类将覆盖其他子类的更改.

在您的问题标题中,您似乎将此称为"原型副本".这是不正确的,因为没有创建副本.Animal.prototype并且Bird.prototype将参考同一个对象.


Bird.prototype = new Animal(); // Solution 2

这是设置继承很长时间的常用方法,但它有两个主要缺点:

  • 如果Animal需要参数,你通过了哪些?传递随机,毫无意义的参数只是为了使函数调用工作似乎是糟糕的设计.
  • Animal 可能有副作用,比如增加一个实例计数器,但是在这一刻你实际上没有创建一个新实例(或者不想),你只想设置继承.

Bird.prototype = Object.create(Animal.prototype); // Solution 1

这就是你现在应该这样做的方式(直到更好的解决方案出现).你真正想做的就是Animal将原型连接到原型链中Bird.它避免了先前解决方案的所有缺点.

为了使其正常工作,您还必须在Animal构造函数内调用构造Bird函数.这就像对super其他编程语言的调用:

function Bird(){
    Animal.call(this);
}
Run Code Online (Sandbox Code Playgroud)

这可确保对新Animal实例所做的任何命令/更改都应用于新Bird实例.

将正确的值分配给constructor原型的属性也是一种好习惯.它通常是指原型"属于"的功能,但在上面的所有解决方案中,Bird.prototype.constructor都将参考Animal.所以我们必须这样做:

Bird.prototype.constructor = Bird;
Run Code Online (Sandbox Code Playgroud)

此属性不在内部使用,因此只有在您自己的代码依赖它时才需要执行此操作.但是,如果您创建一个供他人使用的库,他们可能会期望该属性必须更正值.


xda*_*azz 0

您可以使用解决方案 1解决方案 2,但不应使用解决方案 3

原因是当你这样做时Bird.prototype = Animal.prototype;,每次改变Bird.prototype也会影响Animal.prototype,因为它们是同一个对象。

例如,您在 上附加一个方法Bird.prototype,那么该方法也将在 上运行Animal,这不会是您想要的。