Javascript“OOP”和具有多级继承的原型 [英] Javascript "OOP" and prototypes with multiple-level inheritance

查看:117
本文介绍了Javascript“OOP”和具有多级继承的原型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Javascript编程的新手,我从面向对象编程的角度来看我的第一个应用程序(确实是游戏)(我知道js不是真正的面向对象,但对于这个特殊的问题,它对我来说更容易像这样开始。)

I'm new to Javascript programming and I'm approaching my first application (a game, indeed) from an object oriented programming perspective (I know js is not really object oriented, but for this particular problem it was easier for me to start like this).

我有一个类的层次结构,其中最顶层(Thing类)定义了相关事物的列表(附件中的游戏)。它由ThingA类继承,由ThingA1和ThingA2类继承。

I have a hierarchy of "classes" where the top-most ("Thing" class) defines a list of related things (attached items in the game). It's inherited by a ThingA class which is inherited by ThingA1 and ThingA2 classes.

最小的例子是:

function Thing() 
{
  this.relatedThings   = [];
}
Thing.prototype.relateThing = function(what)
{
  this.relatedThings.push(what);
}

ThingA.prototype = new Thing();
ThingA.prototype.constructor = ThingA;
function ThingA()
{
}

ThingA1.prototype = new ThingA();
ThingA1.prototype.constructor = ThingA1;
function ThingA1()
{

}

ThingA2.prototype = new ThingA();
ThingA2.prototype.constructor = ThingA2;
function ThingA2()
{    
}

var thingList = [];

thingList.push(new ThingA());
thingList.push(new ThingA1());
thingList.push(new ThingA2());
thingList.push(new ThingA2());
thingList.push(new Thing());

thingList[1].relateThing('hello');

在代码结束时,执行relatedThing时,每个ThingA,ThingA1和ThingA2都会运行执行它(不是数组中的最后一个Thing对象)。我发现如果我在ThingA原型中定义了relatedThing函数,它将正常工作。由于游戏的设计方式,我宁愿不必这样做。

At the end of the code, when the relateThing is executed, every ThingA, ThingA1 and ThingA2 is going to execute it (not the last "Thing" object in the array). I've found if I define the relateThing function in the ThingA prototype, it will work right. Because of how the game is designed I'll prefer not to have to do that.

也许我不了解原型如何在javascript中运行。我知道函数在所有对象之间共享,但我想执行将是个体的。有人可以解释为什么会发生这种情况以及如何解决这个问题?我不知道我做的继承是错误的,还是原型定义,或者是什么。

Maybe I'm not understanding something about how the prototypes work in javascript. I know the function is shared among all the objects, but i guess the execution would be individual. Could somebody explain why is this happening and how to solve it? I don't know if I'm doing the inheritance wrong, or the prototypes definitions, or what.

提前致谢。

推荐答案

欢迎来到原型链!

让我们看看你的例子中的样子。

Let's see what it looks like in your example.

当您调用 new Thing()时,您正在创建一个具有属性 relatedThings 指的是一个数组。所以我们可以说我们有这个:

When you call new Thing(), you are creating a new object with a property relatedThings which refers to an array. So we can say we have this:

+--------------+
|Thing instance|
|              |
| relatedThings|----> Array
+--------------+     

然后,您将此实例分配给 ThingA.prototype

You are then assigning this instance to ThingA.prototype:

+--------------+
|    ThingA    |      +--------------+
|              |      |Thing instance|
|   prototype  |----> |              |
+--------------+      | relatedThings|----> Array
                      +--------------+

因此 ThingA 的每个实例都将继承自 Thing 实例。现在你要创建 ThingA1 ThingA2 并分配一个新的 ThingA 实例,后来创建 ThingA1 ThingA2 的实例(以及 ThingA Thing ,但此处未显示)。

So each instance of ThingA will inherit from the Thing instance. Now you are going to create ThingA1 and ThingA2 and assign a new ThingA instance to each of their prototypes, and later create instances of ThingA1 and ThingA2 (and ThingA and Thing, but not shown here).

现在关系就是这个( __ proto __ 是一个内部属性,连接一个对象及其原型):

The relationship is now this (__proto__ is an internal property, connecting an object with its prototype):

                               +-------------+
                               |   ThingA    |
                               |             |    
+-------------+                |  prototype  |----+
|   ThingA1   |                +-------------+    |
|             |                                   |
|  prototype  |---> +--------------+              |
+-------------+     |    ThingA    |              |
                    | instance (1) |              |
                    |              |              |
+-------------+     |  __proto__   |--------------+ 
|   ThingA1   |     +--------------+              |
|   instance  |           ^                       |
|             |           |                       v
|  __proto__  |-----------+                 +--------------+
+-------------+                             |Thing instance|
                                            |              |
                                            | relatedThings|---> Array
+-------------+     +--------------+        +--------------+ 
|   ThingA2   |     |   ThingA     |              ^
|             |     | instance (2) |              |
|  prototype  |---> |              |              |
+-------------+     |  __proto__   |--------------+
                    +--------------+
+-------------+           ^
|   ThingA2   |           |  
|   instance  |           |
|             |           |
|  __proto__  |-----------+
+-------------+                        

因此,每个 ThingA ThingA1 的实例或 ThingA2 指的是同一个数组实例

And because of that, every instance of ThingA, ThingA1 or ThingA2 refers to one and the same array instance.

这是

This is not what you want!

要解决此问题,任何子类的每个实例都应该具有自己的 relatedThings 属性。您可以通过在每个子构造函数中调用父构造函数来实现此目的,类似于在其他语言中调用 super()

To solve this problem, each instance of any "subclass" should have its own relatedThings property. You can achieve this by calling the parent constructor in each child constructor, similar to calling super() in other languages:

function ThingA() {
    Thing.call(this);
}

function ThingA1() {
    ThingA.call(this);
}

// ...

此调用 Thing ThingA 并将这些内的设置为第一个您传递给 .call 的参数。了解有关 .call 的更多信息 [MDN] [MDN]

This calls Thing and ThingA and sets this inside those function to the first argument you pass to .call. Learn more about .call [MDN] and this [MDN].

仅此一项就会将上图改为:

This alone will change the above picture to:

                               +-------------+
                               |   ThingA    |
                               |             |    
+-------------+                |  prototype  |----+
|   ThingA1   |                +-------------+    |
|             |                                   |
|  prototype  |---> +--------------+              |
+-------------+     |    ThingA    |              |
                    | instance (1) |              |
                    |              |              |
                    | relatedThings|---> Array    |
+-------------+     |  __proto__   |--------------+ 
|   ThingA1   |     +--------------+              |
|   instance  |           ^                       |
|             |           |                       |
|relatedThings|---> Array |                       v
|  __proto__  |-----------+                 +--------------+
+-------------+                             |Thing instance|
                                            |              |
                                            | relatedThings|---> Array
+-------------+     +--------------+        +--------------+ 
|   ThingA2   |     |   ThingA     |              ^
|             |     | instance (2) |              |
|  prototype  |---> |              |              |
+-------------+     | relatedThings|---> Array    |
                    |  __proto__   |--------------+
                    +--------------+
+-------------+           ^
|   ThingA2   |           |  
|   instance  |           |
|             |           |
|relatedThings|---> Array | 
|  __proto__  |-----------+
+-------------+

如您所见,每个实例都有自己的 relatedThings 属性,该属性引用不同的数组实例。原型链中仍有 relatedThings 属性,但实例属性都是 shadowed

As you can see, each instance has its own relatedThings property, which refers to a different array instance. There are still relatedThings properties in the prototype chain, but they are all shadowed by the instance property.

另外,不要将原型设置为:

Also, don't set the prototype with:

ThingA.prototype = new Thing();

您实际上不想创建新的 Thing 实例在这里。如果 Thing 预期参数会怎样?你会通过哪一个?如果调用 Thing 构造函数有副作用怎么办?

You actually don't want to create a new Thing instance here. What would happen if Thing expected arguments? Which one would you pass? What if calling the Thing constructor has side effects?

实际上想要的是将 Thing.prototype 连接到原型链中。您可以使用 Object.create [MDN]

What you actually want is to hook up Thing.prototype into the prototype chain. You can do this with Object.create [MDN]:

ThingA.prototype = Object.create(Thing.prototype);

构造函数发生的任何事情( Thing )我们实际创建一个新的 ThingA 实例(通过调用 Thing.call(this))如上所示)。

Anything that happens when the constructor (Thing) is executed will happen later, when we actually create a new ThingA instance (by calling Thing.call(this) as shown above).

这篇关于Javascript“OOP”和具有多级继承的原型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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