Ale*_*lls 11 javascript typescript ecmascript-6
好吧我们有这个:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
printName() {
console.log('this.name');
}
}
Run Code Online (Sandbox Code Playgroud)
我想要做的是定义printName,如下所示:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
// we want to define printName using a different scope
// this syntax is close, but is *not* quite correct
printName: makePrintName(foo, bar, baz)
}
Run Code Online (Sandbox Code Playgroud)
其中makePrintName是一个仿函数,如下所示:
exports.makePrintName = function(foo, bar, baz){
return function(){ ... }
};
Run Code Online (Sandbox Code Playgroud)
这可能与ES6有关吗?我的编辑器和TypeScript不喜欢这个
注意:使用ES5,这很容易做到,看起来像这样:
var Car = function(){...};
Car.prototype.printName = makePrintName(foo, bar, baz);
Run Code Online (Sandbox Code Playgroud)
使用类语法,目前最适合我的方法是:
const printName = makePrintName(foo,bar,baz);
class Car {
constructor(){...}
printName(){
return printName.apply(this,arguments);
}
}
Run Code Online (Sandbox Code Playgroud)
但那并不理想.如果您尝试使用类语法来执行ES5语法可以执行的操作,您将看到问题.因此,ES6类包装器是一个漏洞抽象.
要查看真实用例,请参阅:
https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L171
使用的问题TestBlock.prototype.startSuite = ...
是,在这种情况下,我不能简单地在线返回类:
https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L67
在JavaScript和TypeScript中执行此操作的首选方法可能因键入系统的限制而有所不同,但如果printName
应该是原型方法而不是实例方法(前者有几个原因有用),则没有太多选项.
可以通过访问器检索原型方法.在这种情况下,它应该优选地被记忆或缓存到变量.
const cachedPrintName = makePrintName(foo, bar, baz);
class Car {
...
get printName(): () => void {
return cachedPrintName;
}
}
Run Code Online (Sandbox Code Playgroud)
它可以懒惰地评估:
let cachedPrintName;
class Car {
...
get printName(): () => void {
return cachedPrintName || cachedPrintName = makePrintName(foo, bar, baz);
}
}
Run Code Online (Sandbox Code Playgroud)
或者它可以直接分配给班级prototype
.在这种情况下,它应该另外输入为类属性,因为TypeScript忽略了prototype
赋值:
class Car {
...
printName(): () => void;
}
Car.prototype.printName = makePrintName(foo, bar, baz);
Run Code Online (Sandbox Code Playgroud)
返回() => void
的函数的类型在哪里makePrintName
.
TypeScript的一种自然方式是不修改类原型,而是扩展原型链并通过mixin类引入新的或修改过的方法.这会在JavaScript中引入不必要的复杂性,但让TypeScript对类型感到满意:
function makePrintNameMixin(foo, bar, baz){
return function (Class) {
return class extends Class {
printName() {...}
}
}
}
const Car = makePrintNameMixin(foo, bar, baz)(
class Car {
constructor() {...}
}
);
Run Code Online (Sandbox Code Playgroud)
此时无法无缝地使用TypeScript装饰器,因为此时不支持类突变.该类还应补充接口以抑制类型错误:
interface Car {
printName: () => void;
}
@makePrintNameMixin(foo, bar, baz)
class Car {
constructor() {...}
}
Run Code Online (Sandbox Code Playgroud)
我还没有看到提到的另一个想法是使用方法装饰器。以下装饰器采用方法实现并将其根据需要放置在原型上:
function setMethod<T extends Function>(value: T) {
return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>): void {
descriptor.value = value;
delete descriptor.get;
delete descriptor.set;
};
}
Run Code Online (Sandbox Code Playgroud)
把它放在图书馆的某个地方。使用方法如下:
class Car {
constructor(name) {
this.kind = 'Car';
this.name = name;
}
@setMethod(makePrintName(foo, bar, baz))
printName() {} // dummy implementation
}
Run Code Online (Sandbox Code Playgroud)
唯一的缺点是,您必须在类中放置具有正确签名的方法的虚拟实现,因为装饰器需要装饰一些东西。但它在运行时的行为完全符合您的要求(它不是为每个实例花费新函数定义的实例方法,也不是每次使用时花费额外函数调用的访问器)。
这有帮助吗?
归档时间: |
|
查看次数: |
361 次 |
最近记录: |