在JavaScript中安全地继承原型 [英] Safely inheriting prototypes in JavaScript

查看:94
本文介绍了在JavaScript中安全地继承原型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我在我的应用程序中搜索一些基本的继承,我可以通过将我的孩子的原型设置为父级来实现。

Let's say I'm shooting for some basic inheritance in my application, I could achieve this by setting the prototype of my child to the parent.

// Parent "class"
var Car = function(year) {
    this.year = year;
};

Car.prototype.drive = function() {
    console.log('Vrooom');
};

// Child "class"
var Toyota = function() {
    Car.apply(this, arguments);
};

Toyota.prototype = Car.prototype;

var myCar = new Car(2010), myToyota = new Toyota(2010);

myCar.drive(); // Vrooom
myToyota.drive(); // Vrooom

似乎工作,但显然很糟糕,因为如果我在我的<上设置一个新方法code> Toyota.prototype ,它将设置在 Car 的原型上。

Seems to work, but is obviously bad because if I set a new method on my Toyota.prototype, it will be set on Car's prototype.

Toyota.prototype.stop = function() {
    console.log('stooop');
};

myCar.stop(); // stooop  <--- bad
myToyota.stop(); // stooop  <--- good

要解决这个问题,而不是 Toyota.prototype = Car.prototype; 我可以添加一个中介:

To solve this, instead of Toyota.prototype = Car.prototype; I can add an intermediary:

var ctor = function() { };
ctor.prototype = Car.prototype;

Toyota.prototype = new ctor();

Toyota.prototype.stop = function() {
    console.log('stooop');
};

myCar.stop(); // throws undefined error  <--- good
myToyota.stop(); // stooop  <--- good

但我不明白为什么会这样。 ctor 创建一个新实例,其原型设置为 Car的原型,然后 Toyota 将其原型设置为该新实例。

But I don't understand why this works. ctor creates a new instance with its prototype set to Car's prototype, and then Toyota sets its prototype to that new instance.

但为什么要创建一个空对象,其原型会被 Toyota 的原型引用?

为什么不在上设置新方法丰田将它设置在 Car 上,就像在第一个例子中一样?
如果我想要几层继承,看起来我需要每次用 new ctor 将它们粘在一起?

But why create an empty object with a prototype that gets referenced by Toyota's prototype?
Why doesn't setting a new method on Toyota set it on Car like it does in the first example? What if I want several layers of inheritance, it seems like I need to glue them together with a new ctor every time?

推荐答案


但为什么要创建一个空对象,其原型被丰田引用
s原型?

But why create an empty object with a prototype that gets referenced by Toyota's prototype?

因为如果你这样做: Toyota.prototype = new Car();

现在丰田的原型是 Car 的一个实例,这意味着除了在链中有 Car 的原型,它还在 Car 构造函数本身中设置了任何属性。基本上你不希望 Toyota.prototype 拥有一个名为 year 的属性,如下所示: Toyota.prototype.year 。因此,有一个像这样的空构造函数要好得多:

Now Toyota's prototype is an instance of Car, which means that in addition to having Car's prototype in the chain, it also has any properties set in the Car constructor itself. Basically you wouldn't want Toyota.prototype to have a property called year like so: Toyota.prototype.year. Because of this it's a lot better to have an empty constructor like so:

var ctor = function() { };
ctor.prototype = Car.prototype;

Toyota.prototype = new ctor();

现在 Toyota.prototype 拥有新ctor ()实例,因为它是原型,而它自己的链中又有 Car.prototype 。这意味着丰田的实例现在可以执行 Car.prototype 中存在的方法。

Now Toyota.prototype has the new ctor() instance as it's prototype, which in turn has Car.prototype in its own chain. This means that instances of Toyota now can execute methods that exist in Car.prototype.



为什么不在丰田上设置新方法将其设置为 Car 之类的它在第一个例子中是

Why doesn't setting a new method on Toyota set it on Car like it does in the first example?

这个: Toyota.prototype = Car.prototype ; 您将丰田的原型设置为与 Car.prototype 包含的对象完全相同。由于它是同一个对象,因此在一个地方更改它也会在其他任何地方更改它。这意味着对象是通过引用而不是通过值传递的,这是另一种说法,当您将对象分配给3个不同的变量时,无论您使用哪个变量,它都是同一个对象。例如,字符串按值传递。以下是字符串示例:

With this: Toyota.prototype = Car.prototype; you're setting Toyota' prototype to be the same exact object as what Car.prototype contains. Since it is the same object, changing it in one place also changes it everywhere else. This means that objects are passed be reference and not by value, which is another way of saying that when you assign an object to 3 different variables, it is the same object regardless of which variable you use. Strings for example are passed by value. Here is an example with strings:

var str1 = 'alpha';
var str2 = str1;
var str3 = str1;

str2 = 'beta';

// Changing str2 doesn't change the rest.
console.log(str1); //=> "alpha"
console.log(str3); //=> "alpha"
console.log(str2); //=> "beta"

现在与对象及其属性进行比较;

Now compare to objects and their properties;

var obj1 = {name: 'joe doe'};
var obj2 = obj1;
var obj3 = obj1;

console.log(obj1.name); //=> "joe doe"
console.log(obj2.name); //=> "joe doe"
console.log(obj3.name); //=> "joe doe"

obj2.name = 'JOHN SMITH';

console.log(obj1.name); //=> "JOHN SMITH"
console.log(obj2.name); //=> "JOHN SMITH"
console.log(obj3.name); //=> "JOHN SMITH"



如果我想要几层继承怎么办...

What if I want several layers of inheritance...

这是另一种创建图层的方法继承:

Here is another way of creating layers of inheritance:

var Car = function(year) {
    this.year = year;
};

Car.prototype.drive = function() {
    console.log('Vrooom');
};

var Toyota = function() {
    Car.apply(this, arguments);
};

// `Object.create` does basically the same thing as what you were doing with `ctor()`
// Check out the documentation for `Object.create` as it takes a 2nd argument too.
Toyota.prototype = Object.create(Car.prototype);


// Create instances
var 
  myCar = new Car(2010), 
  myToyota = new Toyota(2010);


// Add method to Toyota's prototype
Toyota.prototype.stop = function() {
    console.log('stooop');
};

让我们现在试试看:

myToyota.stop(); //=> 'stooop'
myCar.stop(); //=> 'TypeError: undefined is not a function'

myCar.drive(); //=> Vrooom
myToyota.drive(); //=> Vrooom

这篇关于在JavaScript中安全地继承原型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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