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