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、内部类以及如何有效地访问父作用域的主要内容,如果未能解决你的问题,请参考以下文章

如何更改内部类中的变量值[closed]

JavaScript是如何工作的:深入类和继承内部原理 + Babel和TypeScript之间转换

如何从类函数内部访问对象属性[重复]

技术篇7.0类的高级特性

更有效地访问 std::vector

htmlspecialchars() - 如何以及何时使用和避免多次使用