Javascript“OOP”和具有多级继承的原型 [英] Javascript "OOP" and prototypes with multiple-level inheritance
问题描述
我是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 $ c每个原型的$ c>实例,后来创建
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 $ c来执行此操作$ c> [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屋!