作为一名C++经验的TypeScript初学者,有一些概念需要了解原理,而不是死记硬背(说的好像学什么可以死记硬背学好似的)。
首先需要清楚:
1. TypeScript编译后生成JavaScript,一切问题都可以转化成对生产JS后的思考;
2. TypeScript不仅兼容JavaScript(TS是JS的超级),而且有新的特性。
今天打算说说自己作为初学者,对interface的理解过程。
C++中 interface 其实和 class 、struct 相同,都可以:
1. 有成员方法
2. 有成员变量
3. 可以被继承
4. 可以继承自多个
看起来只是通过不同关键字(其实还有对C的兼容,历史包袱),做非强制约定,一般(注意是一般):
interface | class | struct | |
设计意图 | 接口约定 | 业务实现 | 纯数据组织,倾向POD |
默认访问 | public | private | public |
成员方法 | 纯虚接口声明 | 都可以 | 无 |
成员变量 | 无 | 都可以 | 有 |
继承关系 | 被继承,自己无法被实例化 | 都可以 | 较少 |
TypeScript中继承有两种(类似java):
1. implement 自 interface,可以有多个;
2. extends 自 class,必须单继承(注意是直接关系一对一,但是可以串联实现多重继承)。
现在有个需求,需要给部分模块提供序列化/反序列化功能。
简单:设计统一接口,需要支持的就实现该接口,根据是否实现该接口判断是否支持序列化/反序列化。
要是C++,很顺利应该就完成了。可是,如下(左侧TS,右侧JS):
Error in code: 'IStreamingArchive' only refers to a type, but is being used as a value here.
看了JS,就能发现,哪有什么IStreamingArchive,interface只是在TS中存在,编译后就没了。也就不能 instanceof 了。
PS:细心看的话,上面有个没错的错误 : let arrA : Array<BaseModule> = new Array<A>(); (留给大家思考)
那怎么办,办法也由 JS 特性(成员都是property)而来:
另外,TS中interface常见有成员变量,也是用来约定实现接口的类一定有这些成员变量。
上面思考题,有一个相关概念对于理解TS个人觉得比较关键:鸭子类型(Duck-Typing)。简单理解就是:不是只有继承自Duck才 is a Duck,如果能有Duck相同的属性(成员变量)、行为(成员方法),那也满足 is a Duck。