在TypeScript中访问外部类的成员

时间:2016-08-02 21:23:04

标签: oop typescript closures inner-classes

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

4 个答案:

答案 0 :(得分:7)

如果你查看代码的编译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;

this此处是class_1而非OuterClass的实例,因此outerField中没有this
此外,您无法从内部类访问外部类的实例。

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

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

答案 1 :(得分:6)

@nitzan的答案很棒。我只是想补充一点,我最近想出了这个,也许它有所帮助:

class Outer {

    constructor() {
        this.val = 1337;
    }

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

}

new (new Outer()).Inner().accessVal(); // 1337

答案 2 :(得分:1)

以下是在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!

不需要任何复杂的事情。

答案 3 :(得分:0)

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

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)