3

引言

继上周的文章《TypeScript 注解(上)》,补充在最后未实现的属性注解。

本文可能需要扎实的JavaScript功底,我尽量给大家通俗地讲解。

实现

建立新项目

上周的项目建立的太不正规了,直接建个文件夹,然后写的TS代码,太过不规范。

这次我们使用npm init初始化一个新的前台项目。

clipboard.png

创建成功后,项目中就出现了我们熟知的package.json文件。

clipboard.png

安装依赖

本次,我们需要使用反射实现一些高级的功能。

反射是指计算机程序在运行时可以访问、检测和修改它本身状态或行为的一种能力。

根据官方文档的环境要求,使用TypeScript反射,我们需要先安装reflect-metadata包。

npm i reflect-metadata --save

属性注解

属性注解在属性上声明,属性注解的表达式在运行期间像函数一样被调用,并带着以下两个参数:

  1. 如果是在静态成员上,则是类的构造函数;如是在实例成员上,则是类的原型。
  2. 成员的名称。

所以,一个标准的属性注解如下所示:返回一个带有两个参数的闭包。

function annotation(target: string) {
    return function(target, propertyKey) {
    }
}

看下面的实例代码:这里直接返回Reflect.metadata代替原闭包,因为metadata方法的返回值,就符合该规范。

clipboard.png

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注解,来添加该字符串应该显示的前缀。

clipboard.png

功能很简单,也就不再赘述了。以后想写类似功能时照葫芦画瓢就是了,这里主要是对一些比较繁琐的代码加以研究。

Symbol

大家想必注意到了这里的Symbol了,这是个什么东西呢?

// 声明唯一的元数据key
const formatMetaDataKey = Symbol("format");

Symbol是一种新的基本数据类型。

Google搜索JavaScript数据类型,发现谷歌的第一条已然过时,面试也常考,这里纠正一下。

clipboard.png

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);

clipboard.png

对象中允许字符串或Symbol作为key,从这个例子我们可以看出,字符串的key不具有唯一性,而Symbolkey能保证唯一,不进行覆盖。

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');

总结

初级程序员的业余生活,学习,学习,学习。

clipboard.png


张喜硕
2.1k 声望423 粉丝

浅梦辄止,书墨未浓。