如何在TypeScript中建立动态原型链?
在JavaScript中,我可以编写一个“派生类”,其“基类”是动态的,代码如下:如何在TypeScript中建立动态原型链?,typescript,prototypal-inheritance,Typescript,Prototypal Inheritance,在JavaScript中,我可以编写一个“派生类”,其“基类”是动态的,代码如下: 函数类(sF){ 函数DynamicBaseClass(iF){this.instanceField=iF;} //编辑:哎呀,从ES6的意义上讲,这不是真正的静态,但它是在 //“基础”原型,重要的是,不在最终对象中。 DynamicBaseClass.prototype.staticField=sF; 返回DynamicBaseClass; } 函数NewDerivedClass(基类){ 函数派生类(iF、
函数类(sF){
函数DynamicBaseClass(iF){this.instanceField=iF;}
//编辑:哎呀,从ES6的意义上讲,这不是真正的静态,但它是在
//“基础”原型,重要的是,不在最终对象中。
DynamicBaseClass.prototype.staticField=sF;
返回DynamicBaseClass;
}
函数NewDerivedClass(基类){
函数派生类(iF、dF){
基类调用(this,iF);
this.derivedField=dF;
}
DerivedClass.prototype=Object.create(baseClass.prototype);
Object.defineProperty(DerivedClass.prototype,'构造函数',{
值:DerivedClass,
可枚举:false,//从“for in”循环中忽略
可写:对
});
DerivedClass.prototype.dump=函数dump(){
console.log(“instanceField=“+this.instanceField+
“derivedField=“+this.derivedField+
“staticField=“+this.staticField+
“base=“+this.\uuuuu proto\uuuuu.\uuuuuu proto\uuuuuu.constructor.name”);
}
返回派生类;
}
var BaseClass 1=NewBaseClass(“动态原型1”);
var BaseClass2=NewBaseClass(“动态原型2”);
new(NewDerivedClass(BaseClass1))(3,33.dump();
new(NewDerivedClass(BaseClass1))(4,44.dump();
new(NewDerivedClass(BaseClass2))(5,55.dump();
new(NewDerivedClass(BaseClass2))(6,66.dump();
//输出:
//instanceField=3 derivedField=33 staticField=DynamicPrototype#1 base=DynamicBaseClass
//instanceField=4 derivedField=44 staticField=DynamicPrototype#1 base=DynamicBaseClass
//instanceField=5 derivedField=55 staticField=DynamicPrototype#2 base=DynamicBaseClass
//instanceField=6 derivedField=66 staticField=DynamicPrototype#2 base=DynamicBaseClass
(这样做有多种原因;在我的例子中,这样做可以节省内存:如果一大群对象都需要几个属性的相同值,它们可以在原型链中高效地共享这些公共值。) 如何在TypeScript中实现类似的效果?如果用于定义类的代码有点难看,也可以,只要可以编写
new(NewDerivedClass(BaseClass))
以使该表达式具有合理的类型。一般解决方案
以下代码在TypeScript中产生相同的效果(staticField
在原型链上,而不是在派生对象上)。但是,请注意,在基类中使用真正的静态
字段更容易:您不需要在NewBaseClass
中编写作为基类
- TypeScript 3.8.3并不完全接受它:它抱怨
,说“一个mixin类必须有一个构造函数,其中包含一个类型为“any[]”的rest参数”。但是,可以使用DerivedClass
抑制此错误/@ts ignore
- TypeScript 3.6.5似乎不理解
是非空的,因此给出了多个错误。它还说“导出函数的返回类型具有或正在使用私有名称‘DerivedClass’”,这很奇怪,因为baseClass
没有导出。后一个错误的解决方法是定义匹配接口并将其用作返回类型:NewDerivedClass
interface DerivedClass_ { new (iF: number, dF: number): { derivedField: number; dump(): void; } }
Object.setPrototypeOf
,MDN警告我们出于性能原因不要使用它。我希望打字的人知道他们在做什么
“廉价”数据共享技术
如果目标只是在多个实例之间共享数据,而不消耗单个实例上的任何内存,那么可以这样做:
interface DynamicClass_ { // not needed in TypeScript 3.8
new (iF: number, dF: number): {
instanceField: number;
derivedField: number;
};
}
function NewClass(staticField: string, foo: any): DynamicClass_ {
class DynamicClass {
constructor(public instanceField: number,
public derivedField: number) { }
dump() {
console.log("instanceField=" + this.instanceField +
" derivedField=" + this.derivedField +
" staticField=" + staticField + // <<<<<<<<<<<<<<<<<<<<<<<<<
" foo=" + foo); // <<<<<<<<<<<<<<<<<<<<<<<<<
}
}
return DynamicClass;
}
ES2015课程
因为extends
关键字可以接受一个变量,所以可以将函数类构造函数转换为ES2015样式的类
函数NewBaseClass(sF:string){
返回舱{
静态场=sF;
instanceField:编号;
构造函数(如果:编号){
this.instanceField=iF;
}
};
}
接口超类类型{
新增(如果:编号):{
instanceField:编号;
静态字段:字符串;
};
}
函数NewDerivedClass(基类:超类类型){
返回类扩展了基类{
derivedField:数字;
构造函数(iF:number,dF:number){
超级(如果有);
this.derivedField=dF;
}
转储(){
console.log(“instanceField=“+this.instanceField+
“derivedField=“+this.derivedField+
“staticField=“+this.staticField”);
}
};
}
var BaseClass 1=NewBaseClass(“动态原型1”);
var BaseClass2=NewBaseClass(“动态原型2”);
new(NewDerivedClass(BaseClass1))(3,33.dump();
new(NewDerivedClass(BaseClass1))(4,44.dump();
new(NewDerivedClass(BaseClass2))(5,55.dump();
new(NewDerivedClass(BaseClass2))(6,66.dump();
//输出:
//instanceField=3 derivedField=33 staticField=动态原型#1
//instanceField=4 derivedField=44 staticField=动态原型#1
//instanceField=5 derivedField=55 staticField=动态原型#2
//instanceField=6 derivedField=66 staticField=动态原型#2
这种方法的一个危险是,您不能接受并修改作为NewDerivedClass一部分的泛型,这会阻止您修改任意类,部分原因是您可能会引入名称冲突。看
使用ES2015static
请注意,上面没有使用Typescript的static
,因为您已经将static字段有效地放在NewBaseClass的匿名原型对象上,而不是放在构造函数本身上。通过在派生函数中引用基类对象,而不是将其视为原始属性,可以很容易地解决这一问题
函数NewBaseClass(sF:string){
返回舱{
static staticField=sF;//“如果一大组对象都需要相同的val
interface DynamicClass_ { // not needed in TypeScript 3.8
new (iF: number, dF: number): {
instanceField: number;
derivedField: number;
};
}
function NewClass(staticField: string, foo: any): DynamicClass_ {
class DynamicClass {
constructor(public instanceField: number,
public derivedField: number) { }
dump() {
console.log("instanceField=" + this.instanceField +
" derivedField=" + this.derivedField +
" staticField=" + staticField + // <<<<<<<<<<<<<<<<<<<<<<<<<
" foo=" + foo); // <<<<<<<<<<<<<<<<<<<<<<<<<
}
}
return DynamicClass;
}
function NewClass(staticField: string): DynamicClass_ {
class DynamicClass {
...
}
let proto: any = DynamicClass.prototype;
proto.staticField = staticField;
return DynamicClass;
}