使用 Object.create 进行继承的好处 [英] Benefits of using `Object.create` for inheritance

查看:32
本文介绍了使用 Object.create 进行继承的好处的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试围绕 ECMAScript 5 中引入的新 Object.create 方法.

I've been trying to wrap my head around the new Object.create method which was introduced in ECMAScript 5.

通常当我想使用继承时,我会这样做:

Usually when I want to use inheritance I do something like this:

var Animal = function(name) { this.name = name; }
Animal.prototype.print = function() { console.log(this.name); }

var Dog = function() 
{ 
  return Animal.call(this, 'Dog'); 
}

Dog.prototype = new Animal();
Dog.prototype.bark = function() { console.log('bark'); }

我只是将一个新创建的 Animal 对象分配给 Dog 的原型,一切都像一个魅力:

I just assign a newly created Animal object to Dog's prototype and everything works like a charm:

var dog1 = new Dog();
dog1.print(); // prints 'Dog'
dog1.bark(); // prints 'bark'
dog1.name; //prints 'Dog'

但是人们(没有解释)说 Dog.prototype = new Animal(); 不是继承的工作方式,我应该使用 Object.create 方法:

but people(without explaining) are saying that Dog.prototype = new Animal(); is not the way inheritance works and that I should use Object.create approach:

Dog.prototype = Object.create(Animal.prototype);

这也有效.

使用 Object.create 有什么好处,还是我遗漏了什么?

What's the benefit of using Object.create or am I missing something?

更新:有人说 Dog.prototype = Animal.prototype; 也可以工作.所以现在我完全糊涂了

UPDATE: Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused

推荐答案

在下面我假设您只对为什么 Object.create 更适合设置继承感兴趣.

In the following I assume you are only interested in why Object.create is preferable for setting up inheritance.

要了解好处,让我们首先阐明 JavaScript 中的类"是由什么组成的.你有两个部分:

To understand the benefits, lets first clarify what a "class" is made of in JavaScript. You have two parts:

  1. 构造函数 函数.此函数包含创建类"实例的所有逻辑,即特定于实例的代码.

  1. The constructor function. This function contains all the logic to create an instance of the "class", i.e. instance specific code.

原型 对象.这是实例继承的对象.它包含应在所有实例之间共享的所有方法(和其他属性).

The prototype object. This is the object the instance inherits from. It contains all methods (and other properties) that should be shared among all instances.

继承建立一个is-a关系,例如,一个Dog is一个Animal.这在构造函数和原型对象方面是如何表达的?

Inheritance establishes an is-a relation, for example, a Dog is an Animal. How is this expressed in terms of constructor function and prototype object?

很明显,狗必须具有与动物相同的方法,即 Dog prototype 对象必须以某种方式合并来自 Animal 的方法原型 对象.有多种方法可以做到这一点.你会经常看到这个:

Obviously a dog must have the same methods as an animal, that is the Dog prototype object must somehow incorporate the methods from the Animal prototype object. There are multiple ways to do this. You will often see this:

Dog.prototype = new Animal();

这是可行的,因为 Animal instance 继承自 Animal prototype 对象.但是这也意味着每只狗都继承自一个特定的Animal 实例.这似乎有点奇怪.实例特定代码不应该只在 constructor 函数中运行吗?突然实例特定代码和原型方法似乎混在一起了.

This works because an Animal instance inherits from the Animal prototype object. But it also implies that every dog inherits from one specific Animal instance. That seems to be a bit strange. Shouldn't instance specific code only be run in the constructor function? Suddenly instance specific code and prototype methods seem to be mixed.

我们实际上并不想在那个时候运行 Animal instance 特定的代码,我们只想要 Animal 中的所有方法原型 对象.这就是 Object.create 让我们做的:

We don't actually want to run Animal instance specific code at that moment, we only want all the methods from the Animal prototype object. That is what Object.create lets us do:

Dog.prototype = Object.create(Animal.prototype);

这里我们创建一个新的Animal实例,我们只获取原型方法.实例特定的代码在它应该在的地方执行,在构造函数中:

Here we are not creating a new Animal instance, we only get the prototype methods. The instance specific code is executed exactly where it should be, inside the constructor:

function Dog() { 
   Animal.call(this, 'Dog'); 
}

最大的优点是 Object.create永远工作.使用 new Animal() 仅在构造函数不需要任何参数时才有效.想象一下,如果构造函数看起来像这样:

The biggest advantage is that Object.create will always work. Using new Animal() only works if the constructor does not expect any arguments. Imagine if the constructor looked like this:

function Animal(name) { 
    this.name = name.toLowerCase();
}

你总是要传递一个字符串给Animal,否则你会得到一个错误.当你做 Dog.prototype = new Animal(??); 时你会通过什么?你传递哪个字符串实际上并不重要,只要传递东西,这希望向你表明这是一个糟糕的设计.

You always have to pass a string to Animal, otherwise you will get an error. What will you pass when you do Dog.prototype = new Animal(??);? It doesn't actually matter which string you pass, as long as pass something, which hopefully shows you that this is bad design.

有人说Dog.prototype = Animal.prototype;也可以.所以现在我完全糊涂了

Some say that Dog.prototype = Animal.prototype; can also work. So now I'm totally confused

添加"从Animal.prototypeDog.prototype 的属性的一切都将工作".但解决方案的质量不同.在这种情况下,您将遇到问题,您添加到 Dog.prototype 的任何方法也将添加到 Animal.prototype.

Everything that "adds" the properties from Animal.prototype to Dog.prototype will "work". But the solutions are of different quality. In this case here you will have the problem that any method you add to Dog.prototype will also be added to Animal.prototype.

示例:

Dog.prototype.bark = function() {
    alert('bark');
};

由于Dog.prototype === Animal.prototype,所有Animal 实例现在都有一个方法bark,这肯定不是你的想.

Since Dog.prototype === Animal.prototype, all Animal instances have a method bark now, which is certainly not what you want.

Object.create(甚至 new Animal)通过创建一个继承自 Animal.prototype 并且这个新对象变成了 Dog.prototype.

Object.create (and even new Animal) add one level of indirection to the inheritance by creating a new object which inherits from Animal.prototype and that new object becomes Dog.prototype.

ES6 中的继承

ES6 引入了一种新的语法来创建构造函数和原型方法,如下所示:

ES6 introduces a new syntax to create constructor functions and prototype methods, which looks like this:

class Dog extends Animal {

  bark() {
    alert('bark');
  }

}

这比我上面解释的更方便,但事实证明,extends 也使用与 Object.create 等效的内部结构来设置继承.请参阅ES6 草案中的第 2 步和第 3 步.
这意味着在 ES5 中使用 Object.create(SuperClass.prototype) 是更正确"的方法.

This is more convenient than what I explained above, but as it turns out, extends also uses an internal equivalent to Object.create to setup inheritance. See steps 2 and 3 in the ES6 draft.
Which means that using Object.create(SuperClass.prototype) is the "more correct" approach in ES5.

这篇关于使用 Object.create 进行继承的好处的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆