TypeScript 注解(下)
引言
继上周的文章《TypeScript
注解(上)》,补充在最后未实现的属性注解。
本文可能需要扎实的JavaScript
功底,我尽量给大家通俗地讲解。
实现
建立新项目
上周的项目建立的太不正规了,直接建个文件夹,然后写的TS
代码,太过不规范。
这次我们使用npm init
初始化一个新的前台项目。
创建成功后,项目中就出现了我们熟知的package.json
文件。
安装依赖
本次,我们需要使用反射实现一些高级的功能。
反射是指计算机程序在运行时可以访问、检测和修改它本身状态或行为的一种能力。
根据官方文档的环境要求,使用TypeScript
反射,我们需要先安装reflect-metadata
包。
npm i reflect-metadata --save
属性注解
属性注解在属性上声明,属性注解的表达式在运行期间像函数一样被调用,并带着以下两个参数:
- 如果是在静态成员上,则是类的构造函数;如是在实例成员上,则是类的原型。
- 成员的名称。
所以,一个标准的属性注解如下所示:返回一个带有两个参数的闭包。
function annotation(target: string) { return function(target, propertyKey) { } }
看下面的实例代码:这里直接返回Reflect.metadata
代替原闭包,因为metadata
方法的返回值,就符合该规范。
import "reflect-metadata"; // 声明唯一的元数据key const formatMetaDataKey = Symbol("format"); // 前缀注解 function prefix(target: string) { // 根据key将前缀存至元数据中 return Reflect.metadata(formatMetaDataKey, target); } class Person { constructor(message: string) { this.message = message; } @prefix("hello, ") message: string; speak(): void { // 获取元数据前缀,key,当前对象,message属性 const prefix = Reflect.getMetadata(formatMetaDataKey, this, "message"); console.log(prefix + this.message); } } const person = new Person("world"); person.speak();
通过在字符串属性上声明的prefix
注解,来添加该字符串应该显示的前缀。
功能很简单,也就不再赘述了。以后想写类似功能时照葫芦画瓢就是了,这里主要是对一些比较繁琐的代码加以研究。
Symbol
大家想必注意到了这里的Symbol
了,这是个什么东西呢?
// 声明唯一的元数据key const formatMetaDataKey = Symbol("format");
Symbol
是一种新的基本数据类型。
去Google
搜索JavaScript
数据类型,发现谷歌的第一条已然过时,面试也常考,这里纠正一下。
JavaScript
共有7
种数据类型,重点!!!
6
种基本数据类型:
Boolean
Null
Undefined
Number
String
Symbol
(ECMAScript 6
新定义)
和Object
。
例子
说来说去,Symbol
到底是个啥玩意?一个例子带你看明白。
let obj = { id: 1 }; obj['id'] = 2; // 覆盖了原id console.log(obj); const id = Symbol('id'); obj[id] = 3; // 添加Symbol key的属性 console.log(obj); const id2 = Symbol('id'); obj[id2] = 6; // 不覆盖原Symbol key console.log(obj);
对象中允许字符串或Symbol
作为key
,从这个例子我们可以看出,字符串的key
不具有唯一性,而Symbol
的key
能保证唯一,不进行覆盖。
Token
这个唯一性覆盖问题就像之前在网上送检项目中遇到的问题,因为项目已停工,也就没有和大家提。这里和大家简单说一下。
使用的全局配置是使用字符串注入的,因为是一个容器,假设我们的框架中也用到了'CONFIG'
的字符串注入,那我们加入的配置就会覆盖原框架配置,给框架注入了错误的对象,然后就出现了错误但是就是找不着原因的一系列问题。
providers: [ { provide: 'CONFIG', useValue: YUNZHI_GLOBAL_CONFIG } ] class TestComponent { constructor(@Inject('CONFIG') private config) { } }
其实Angular
已经解决,以后不要再通过字符串注入,推荐通过InjectionToken
注入。
const CONFIG_TOKEN = new InjectionToken<VALUE_TYPE>('CONFIG');
总结
初级程序员的业余生活,学习,学习,学习。