我是 Javascript 编程的新手,我正在从面向对象编程的 Angular 来处理我的第一个应用程序(实际上是一个游戏)(我知道 js 并不是真正的面向对象,但对于这个特定的问题,它对我来说更容易像这样开始)。
我有一个“类”层次结构,其中最顶层(“事物”类)定义了相关事物(游戏中的附加项目)的列表。它由 ThingA 类继承,而 ThingA 类又由 ThingA1 和 ThingA2 类继承。
最小的例子是:
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');
在代码的最后,当执行 relateThing 时,每个 ThingA、ThingA1 和 ThingA2 都将执行它(不是数组中的最后一个“Thing”对象)。我发现如果我在 ThingA 原型(prototype)中定义 relateThing 函数,它将正常工作。由于游戏的设计方式,我宁愿不必这样做。
也许我不太了解原型(prototype)在 javascript 中的工作原理。我知道该函数在所有对象之间共享,但我想执行将是单独的。有人可以解释为什么会发生这种情况以及如何解决吗?我不知道是我做错了继承,还是原型(prototype)定义,还是什么。
提前致谢。
最佳答案
欢迎来到原型(prototype)链!
让我们看看它在您的示例中是什么样子。
当您调用 new Thing() 时,您正在创建一个具有属性 relatedThings 的新对象它指的是一个数组。所以我们可以说我们有这个:
+--------------+
|Thing instance|
| |
| relatedThings|----> Array
+--------------+
然后您将此实例分配给 ThingA.prototype :
+--------------+
| ThingA | +--------------+
| | |Thing instance|
| prototype |----> | |
+--------------+ | relatedThings|----> Array
+--------------+
所以 ThingA 的每个实例将从 Thing 继承实例。现在您要创建 ThingA1和 ThingA2并分配一个新的 ThingA实例到他们的每个原型(prototype),然后创建 ThingA1 的实例和 ThingA2 (以及 ThingA 和 Thing ,但此处未显示)。
现在的关系是这样的(__proto__ 是一个内部属性,将对象与其原型(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 引用同一个数组实例。
这不是您想要的!
要解决这个问题,任何“子类”的每个实例都应该自己 relatedThings属性(property)。您可以通过在每个子构造函数中调用父构造函数来实现此目的,类似于调用 super()在其他语言中:
function ThingA() {
Thing.call(this);
}
function ThingA1() {
ThingA.call(this);
}
// ...
这调用了 Thing和 ThingA并设置 this在这些函数中,您传递给 .call 的第一个参数.了解有关 .call [MDN] 的更多信息和 this [MDN] .
仅此一项就会将上图更改为:
+-------------+
| 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原型(prototype)链中的属性,但它们都被实例属性遮蔽。
此外,不要将原型(prototype)设置为:
ThingA.prototype = new Thing();
您实际上并不想创建一个新的 Thing在这里举例。如果 Thing 会发生什么预期的论点?你会通过哪一个?如果调用 Thing 怎么办?构造函数有副作用?
你实际上想要的是连接 Thing.prototype进入原型(prototype)链。你可以用 Object.create [MDN] 来做到这一点:
ThingA.prototype = Object.create(Thing.prototype);
执行构造函数(Thing)时发生的任何事情都会在我们实际创建新的ThingA 时发生。实例(如上所示调用 Thing.call(this))。
关于Javascript "OOP"和具有多级继承的原型(prototype),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15040955/
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub
我在新的Debian6VirtualBoxVM上安装RVM时遇到问题。我已经安装了所有需要的包并使用下载了安装脚本(curl-shttps://rvm.beginrescueend.com/install/rvm)>rvm,但以单个用户身份运行时bashrvm我收到以下错误消息:ERROR:Unabletocheckoutbranch.安装在这里停止,并且(据我所知)没有安装RVM的任何文件。如果我以root身份运行脚本(对于多用户安装),我会收到另一条消息:Successfullycheckedoutbranch''安装程序继续并指示成功,但未添加.rvm目录,甚至在修改我的.bas
我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#