Javascript、内部类以及如何高效访问父作用域

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4768586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 14:49:44  来源:igfitidea点击:

Javascript, inner classes, and how to access parent scope efficiently

javascriptoopclosures

提问by Cheeso

In Javascript, I would like to define a class with an inner (or nested) class. Within the inner class I'd like to be able to get access to the parent instance. How can I do this efficiently?

在 Javascript 中,我想定义一个带有内部(或嵌套)类的类。在内部类中,我希望能够访问父实例。我怎样才能有效地做到这一点?

Some code will show what I mean. Suppose I define a class, MyType1, which exposes several properties and one function, SayHello:

一些代码将显示我的意思。假设我定义了一个类 MyType1,它公开了几个属性和一个函数SayHello

(function(){
    MyType1 = function(name){
        this.TypeName = "MyType1";
        this.Name = name;
    };

    MyType1.prototype.SayHello = function() {
        say(this.Name + " says hello...");
    };
})();

Ok, now, starting from there, I want to add an "inner class" to MyType1, so I add some new code so that it looks like this:

好的,现在,从那里开始,我想向 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...");
    };
})();

Now I can use these classes like this:

现在我可以像这样使用这些类:

var x = new MyType1("Victor");
x.SayHello();

var c = new x.Child("Elizabeth");
c.Introduce();


that all works. But it defines a new Child function (or type, if you like) for every instance of MyType1. What I'd like to do is get access to the parent class scope, without resorting to that inefficiency. Something like this:

一切正常。但它为 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;

})();

But, this doesn't work. The parentNamevar is out of scope, of course.

但是,这行不通。该parentName变种是超出范围,当然。

Is there an efficient way for the Child instance (in the constructor, or in any class function) to gain access to the parent (MyType2) instance?

Child 实例(在构造函数中,或在任何类函数中)是否有一种有效的方法来访问父(MyType2)实例?



I know that I could define the Child class to be an independent, non-nested class, then in the ctor for that, just pass the Parent instance. But this creates N references to the parent instance, one for every Child instance. That seems like an inefficiency I'd like to avoid.

我知道我可以将 Child 类定义为一个独立的非嵌套类,然后在 ctor 中为此,只需传递 Parent 实例。但这会创建 N 个对父实例的引用,每个子实例一个。这似乎是我想避免的低效率。

thanks for any tips.

感谢您提供任何提示。



EDIT- the reason I want the Child to have access to the parent instance, is that the parent holds an object that is fairly expensive to create - something like a db connection - and I'd like the child to be able to utilize that thing.

编辑- 我希望孩子能够访问父实例的原因是,父对象拥有一个创建起来相当昂贵的对象 - 类似于数据库连接 - 我希望孩子能够利用那个东西.

采纳答案by user85461

It would probably help you out if you do away with notions like "type", "class", etc. when dealing with javascript. In javascript, there is no differentiation from "type", "class", "function", "instance", or "object" -- it's "object" all the way down.

如果您在处理 javascript 时摒弃诸如“类型”、“类”等概念,它可能会对您有所帮助。在 javascript 中,与“类型”、“类”、“函数”、“实例”或“对象”没有区别——它一直是“对象”。

Since every "type" is an "object" and is mutable, you get nothing of the sort of strong-typed efficiency gains you might get from Java or C++ by reusing a single type definition. Think of the "new" operator in javascript as something like "clone the definition and call the constructor", after which the definition of the instance could still be changed.

由于每个“类型”都是一个“对象”并且是可变的,因此您无法通过重用单个类型定义从 Java 或 C++ 中获得那种强类型的效率增益。将 javascript 中的“new”运算符视为“克隆定义并调用构造函数”之类的东西,之后仍然可以更改实例的定义。

So go with your first, working example: you won't get any gains by doing something different.

因此,请使用您的第一个工作示例:通过做不同的事情,您不会获得任何收益。

回答by htatche

This is what I came up after many hours:

这是我在几个小时后想到的:

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);

This way you can instantiate as many Parents as you want, with their Childs underneath, and every Child instance will have access to it's parent instance through the variable parent.

通过这种方式,您可以根据需要实例化任意数量的父级,其子级位于下方,并且每个子级实例都可以通过变量parent访问其父级实例。

回答by David Tang

The only way I can think of is to pass in the parent object to the Child constructor:

我能想到的唯一方法是将父对象传递给子构造函数:

MyType2.Child = function (parent, name) {
    this.parent = parent;
    this.name = name;
    this.Description = this.parent.name + "'s child, " + name;
};

And instantiate it with:

并实例化它:

var x = new MyType2("Victor");

var c = new MyType2.Child(x, "Elizabeth");

My justification is that it makes more sense that the Childconstructor is a "static" property of MyType2, instead of the instantiated object xin your example, since we are talking about typeshere, which are the same across all instances of MyType2.

我的理由是,Child构造函数是 的“静态”属性MyType2而不是x示例中的实例化对象更有意义,因为我们在这里讨论的是类型,它们在 的所有实例中都是相同的MyType2

回答by Max Zlotskiy

I haven't tested this, but you should be able to use JSON for this:

我还没有测试过这个,但你应该可以使用 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);

Now there may be many issues with this, functional or stylistic. But it is an alternative from the other approaches posted here.

现在可能有很多问题,功能或风格。但它是此处发布的其他方法的替代方法。

回答by Todd

This is one way to do it. This declares an inner object - which is kindalike declaring an inner class and immediately getting an instance of it. A reference to the outer class is simply added as a object attribute in the declaration.

这是一种方法。这声明了一个内部对象 - 这有点像声明一个内部类并立即获得它的一个实例。对外部类的引用只是作为对象属性添加到声明中。

// 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);
    }
}

or if you want an inner class you can create instances of later...

或者如果你想要一个内部类,你可以创建稍后的实例......

// 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));
    }
}