Javascript、内部类以及如何有效地访问父作用域
Posted
技术标签:
【中文标题】Javascript、内部类以及如何有效地访问父作用域【英文标题】:Javascript, inner classes, and how to access parent scope efficiently 【发布时间】:2011-06-13 16:56:36 【问题描述】:在 javascript 中,我想定义一个具有内部(或嵌套)类的类。在内部类中,我希望能够访问父实例。我怎样才能有效地做到这一点?
一些代码会显示我的意思。假设我定义了一个类 MyType1,它公开了几个属性和一个函数SayHello
:
(function()
MyType1 = function(name)
this.TypeName = "MyType1";
this.Name = name;
;
MyType1.prototype.SayHello = function()
say(this.Name + " says hello...");
;
)();
好的,现在,从那里开始,我想在 MyType1 中添加一个“内部类”,所以我添加了一些新代码,使其看起来像这样:
(function()
MyType1 = function(name)
this.TypeName = "MyType1";
this.Name = name;
var parentName = name;
this.Child = function(name)
this.Description = parentName + "'s child, " + name;
;
this.Child.prototype.Introduce = function()
say(this.Description + ", greets you...");
;
;
MyType1.prototype.SayHello = function()
say(this.Name + " says hello...");
;
)();
现在我可以像这样使用这些类:
var x = new MyType1("Victor");
x.SayHello();
var c = new x.Child("Elizabeth");
c.Introduce();
一切正常。但它为 MyType1 的每个实例定义了一个新的 Child 函数(或 type,如果你愿意的话)。我想做的是访问父类范围,而不是利用这种低效率。 像这样的:
(function()
MyType2 = function(name)
this.TypeName = "MyType2";
this.Name = name;
this.Prop1 = 1872;
var parentName = name;
;
MyType2.prototype.SayHello = function()
say(this.Name + " says hello...");
;
var c1 = function(name)
this.Description = parentName + "'s child, " + name;
// ^^ no go! ^^
;
c1.prototype.Introduce = function()
say(this.Description + ", greets you...");
;
MyType2.prototype.Child = c1;
)();
但是,这不起作用。当然,parentName
变量超出了范围。
子实例(在构造函数中,或在任何类函数中)是否有有效的方法来访问父 (MyType2) 实例?
我知道我可以将 Child 类定义为一个独立的非嵌套类,然后在 ctor 中,只需传递 Parent 实例。但这会创建 N 个对父实例的引用,每个子实例一个。这似乎是我想避免的低效率。
感谢任何提示。
EDIT - 我希望 Child 能够访问父实例的原因是,父实例拥有一个创建起来相当昂贵的对象 - 类似于 db 连接 - 我会喜欢孩子能够利用那个东西。
【问题讨论】:
呃,还有更多滥用 Javascript 来引入“OOP”的废话。这种语言没有类:如果你想要它们,请使用有类的东西! 您可能会发现这很有用:blog.niftysnippets.org/2009/09/… 这是一组帮助函数(及其解释),提供了一种简单但有效的方法来创建通过原型继承创建的“类”的“子类” .看起来你是手动完成的,所以它可能会为你省点麻烦。 @Tomalek:你说的很对,当然,JavaScript 没有类。它是面向对象的,但确实具有继承性。 @Crowder :我没有进行原型继承。这是一个嵌套/内部类。此示例中没有继承。 @Vidas - anon fn 仅用于在我的代码模块中确定范围帮助。它没有为示例添加任何内容。 @Tomalak - 听起来你对我用 my 代码做什么有疑问。嗯。有没有想过为此去看治疗师? @LightnessRacesinOrbit 这样的可憎? developer.mozilla.org/en-US/docs/Web/JavaScript/… 【参考方案1】:这是一种方法。这声明了一个内部对象 - 有点 就像声明一个内部类并立即获取它的一个实例。对外部类的引用只是作为对象属性添加到声明中。
// ES6 - example of an inner object.
class DancingFoo
constructor(radio)
this._radioListener =
outer: this,
onIsPlaying() this.outer._dancing = true; ,
onStoppedPlaying() this.outer._dancing = false;
radio.attachListener(this._radioListener);
或者如果你想要一个内部类,你可以创建稍后的实例......
// ES6 inner class example
class DancingFoo
constructor(radio)
let RadioListener = class
constructor(outer) this.outer = outer;
onIsPlaying() this.outer._dancing = true;
onStoppedPlaying() this.outer._dancing = false;
radio.attachListener(new RadioListener(this));
【讨论】:
【参考方案2】:我尚未对此进行测试,但您应该可以为此使用 JSON:
//code here
var number =
real :
value : 0, //default value
rational :
integer :
isNegative : false,
value : 0 //default value
,
imaginary :
//code
;
var number2 = Object.create(number.rational.integer.prototype);
现在可能存在很多问题,无论是功能上的还是风格上的。但它是此处发布的其他方法的替代方法。
【讨论】:
【参考方案3】:这是我几个小时后想出的:
var Parent = function()
this.name = "Parent";
this.Child = Child;
this.Child.prototype.parent = this;
var Child = function()
var parent = new Parent();
var child = new parent.Child();
console.log(child.parent.name);
通过这种方式,您可以实例化任意数量的父母,以及他们的孩子 在下面,每个子实例都可以访问它的父实例 通过变量parent。
【讨论】:
【参考方案4】:如果您在处理 javascript 时摒弃“类型”、“类”等概念,它可能会对您有所帮助。在 javascript 中,与“类型”、“类”、“函数”、“实例”或“对象”没有区别——它一直是“对象”。
由于每个“类型”都是一个“对象”并且是可变的,因此您无法通过重用单个类型定义从 Java 或 C++ 中获得强类型的效率提升。将 javascript 中的“new”运算符想象为“克隆定义并调用构造函数”之类的东西,之后仍然可以更改实例的定义。
因此,请使用您的第一个有效示例:做不同的事情不会获得任何收益。
【讨论】:
【参考方案5】:我能想到的唯一方法是将父对象传递给 Child 构造函数:
MyType2.Child = function (parent, name)
this.parent = parent;
this.name = name;
this.Description = this.parent.name + "'s child, " + name;
;
并用以下方式实例化它:
var x = new MyType2("Victor");
var c = new MyType2.Child(x, "Elizabeth");
我的理由是Child
构造函数是MyType2
的“静态”属性而不是您的示例中的实例化对象x
更有意义,因为我们正在谈论类型 在这里,它们在 MyType2
的所有实例中都是相同的。
【讨论】:
以上是关于Javascript、内部类以及如何有效地访问父作用域的主要内容,如果未能解决你的问题,请参考以下文章