【问题标题】:Access members of outer class in TypeScript在 TypeScript 中访问外部类的成员
【发布时间】:2016-12-08 09:55:37
【问题描述】:

从 TypeScript 1.6 开始,我们可以使用 class expressions 轻松创建内部类。在其他以 OOP 为中心的语言(如 Java)中,内部类可以访问外部类的成员 even private ones

这种行为类似于闭包的概念,其中函数可以从定义它的范围访问变量。

为什么我不能在 TypeScript 中实现这一点? ECMAScript 2015 中的类规范在这里起作用吗?

呈现预期行为的代码:

class OuterClass {
    private outerField = 1337;

    public InnerClass = class { 
        public accessOuter() {
            return this.outerField; // outerField not defined
        }
    }
}

var outer = new OuterClass();
var inner = new outer.InnerClass();
var win = inner.accessOuter();

【问题讨论】:

标签: oop typescript closures inner-classes


【解决方案1】:

如果您查看代码的已编译 javascript,就会更容易理解为什么不能这样做:

var OuterClass = (function () {
    function OuterClass() {
        this.outerField = 1337;
        this.InnerClass = (function () {
            function class_1() {
            }
            class_1.prototype.accessOuter = function () {
                return this.outerField; // outerField not defined
            };
            return class_1;
        }());
    }
    return OuterClass;
}());

如您所见,outerField 被定义为OuterClass 的成员,如下所示:

this.outerField = 1337;

当您尝试在 InnerClass 中访问它时:

return this.outerField;

但这里的thisclass_1 的实例,而不是OuterClass,所以this 中没有outerField
此外,您无法从内部类访问外部类的实例。

这个在java中的解决方式是这样的:

class OuterClass {
    private int outerField = 1337;

    public class InnerClass {
        public int accessOuter() {
            return OuterClass.this.outerField;
        }
    }
}

但 typescript/javascript 中没有与 OuterClass.this.outerField 等效的内容。
看看 typescript 内部类更像 java 中的静态内部类,但在这里你也只能访问公共属性:

class OuterClass {
    public static outerField = 1337; // has to be public

    public InnerClass = class { 
        public accessOuter() {
            return OuterClass.outerField;
        }
    }
}

您可以将外部类的实例传递给内部类:

class OuterClass {
    public outerField = 1337;

    public InnerClass = class {
        constructor(private parent: OuterClass) {}

        public accessOuter() {
            return this.parent.outerField;
        }
    }
}

但同样,您需要公开outerField


编辑

如果你想实现一些模拟所需行为的东西(也就是说,内部类实例可以访问私有的外部类成员),那么你可以这样做:

interface OuterClassProxy {
    outerField: number;
}

interface IInnerClass {}

class OuterClass {
    private outerField = 1337;

    static InnerClass = class implements IInnerClass {
        constructor(private parent: OuterClassProxy) {}

        public accessOuter() {
            return this.parent.outerField;
        }
    }

    public createInnerClass(): IInnerClass {
        let outerClassInstance = this;

        return new OuterClass.InnerClass({
            get outerField(): number {
                return outerClassInstance.outerField;
            },
            set outerField(value: number) {
                outerClassInstance.outerField = value;
            }
        });
    }
}

这是相当多的工作,但它会做到的。

【讨论】:

    【解决方案2】:

    @Nitzan 的回答很棒。我只是想补充一下,我最近想出了这个,也许它有帮助:

    class Outer {
    
        constructor() {
            this.val = 1337;
        }
    
        get Inner() {
            let Outer = this;
            return class {
                accessVal() { return Outer.val; }
            }
        }
    
    }
    
    new (new Outer()).Inner().accessVal(); // 1337
    

    【讨论】:

    • 为使用它的内部类添加一个接口可能是个好主意
    【解决方案3】:

    这是在 Typescript 中执行此操作的正确方法:

    class OuterClass {
      private outerField = 1337;
    
      get InnerClass() {
        const thatOuterField = this.outerField // <-- Notice this addition
        return   class {
          public accessOuter() {
            return thatOuterField; // outerField not defined
          }
        }
      }
    
    
    }
    
    let outer = new OuterClass();
    let inner = new outer.InnerClass();
    let win = inner.accessOuter();
    
    alert(win); // test works!
    

    不需要任何复杂的东西。

    【讨论】:

    • 这是 Kosmas 6 个月前发布的相同方法
    • 虽然你不能修改 outerField...
    【解决方案4】:

    这个对我来说并没有那么糟糕:

    function use<T>(value: T) {return new class {with<U>(f: (value: T) => U) {return f(value)}}}
    
    class OuterClass {
        private outerField = 1337;
    
        InnerClass = use(this).with(outerThis => class { 
            accessOuter() {
                return outerThis.outerField; // outerField not defined
            }
        }
    }
    const outer = new OuterClass()
    const inner = new outer.InnerClass()
    const win = inner.accessOuter()
    console.log(win)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-25
      • 2011-08-11
      • 2018-06-26
      • 2017-01-21
      • 2013-10-21
      • 1970-01-01
      • 2012-09-02
      • 1970-01-01
      相关资源
      最近更新 更多