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

查看:22
本文介绍了使用 `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 isAnimal.这如何用构造函数和原型对象表示?

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 函数中运行吗?突然,instance 特定代码和 prototype 方法似乎混在一起了.

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实例,我们只得到原型方法.instance 特定的代码在构造函数内部准确地执行:

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(??); 时你会传递什么?实际上,你传递哪个字符串并不重要,只要传递 something,希望这能告诉你这是一个糟糕的设计.

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.prototype 属性添加"到 Dog.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.
这意味着使用 Object.create(SuperClass.prototype) 是 ES5 中更正确"的方法.

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天全站免登陆