前言
在3月底,js的装饰器提案终于进入了stage3,同时其metadata部分单独拆开仍处于stage2阶段([详见](https://github.com/tc39/proposal-decorators/pull/454))。但是此装饰器却非平时我们广泛使用的装饰器。通过本文我们将了解下该js提案下装饰器的用法并对比和先前装饰器提案下用法的区别
decorator提案的历史
在[babel-plugin-proposal-decorators](https://babeljs.io/docs/en/babel-plugin-proposal-decorators#docsNav)的文档我们可以看到,decorator提案之前主要经历了3个阶段 目前进入stage3阶段移除metadata的版本共4个版本。下文分别简称(legacy、2018-09、2021-12、stage3)
- legacy
stage 1阶段的提案,也是目前广为使用的用法,也基本等同于Typescript中开启
experimentalDecorators
的用法 - 2018-09 在2018.9进入stage2阶段后的提案,此时用法已经完全和stage1不一样
- 2021-12 2021.12针对此前的stage2提案又做了一次修改,用法又做了一点小修改
- stage3
最近正式进入stage3的提案。对比2021-12只是去掉了
metadata
部分,提案本身没有太大的改变。不出意外这也是以后作为标准的装饰器
详细用法
legacy
我们广为使用的用法。即Typescript中tsconfig中配置experimentalDecorators:true
{
"compileOptions": {
"experimentalDecorators": true
}
}
或者@babel/plugin-proposal-decorators
配置
legacy: true
。注意:最新的@babel/plugin-proposal-decorators
已经将该配置迁移到version
字段,即version: legacy
legacy
下的装饰器更具体用法可以参考此前写的一篇文章2020的最后一天,不妨了解下装饰器。
装饰器函数的签名主要如下
代码语言:javascript复制 type decorator = (
target: Target | Target.prototype,
propertyKey: string,
descriptor: PropertyDescriptor
) => Function | void;
stage3
本次进入stage3提案的用法
装饰器函数签名如下:
代码语言:javascript复制type Decorator = (value: Input, context: {
kind: string;
name: string | symbol;
access: {
get?(): unknown;
set?(value: unknown): void;
};
isPrivate?: boolean;
isStatic?: boolean;
addInitializer?(initializer: () => void): void;
}) => Output | void;
装饰器函数包含两个入参参数
1、被装饰的值本身
2、被装饰值的上下文信息
- kind :
"class"|"method"|"getter"|"setter"|"field"|"accessor"
。表示装饰器的类型 - name 装饰值的名称
- access 同个该属性读写值
- isStatic 是否静态属性
- isPrivate 是否私有属性
- addInitializer 用于执行一些初始化逻辑
各种不同类型的装饰器如下
此外stage3对比legacy提案特有的两个用法
2018-09&2021-12
由于这两种用法在实际中很少特别使用这里只作简单差异化介绍
总结
stage3对比legacy
- 除了上面提到的语法区别。legacy装饰器是用“Target”(由当前被装饰目标决定是类本身还是类的原型)调用的,而在stage3中,不再提供这个
Target
给装饰器函数 - legacy装饰器会提供一个完整的
descriptor
对象,而stage3中只提供被装饰的值以及和它有关的上下文对象。在stage3中修改一个属性的attribute是不可能的,并且 getter 和 setter 不是“合并”而是单独被装饰
stage3对比2018-09
- 上面提到的语法的区别
- 功能上stage3是2018-09的子集
参考
tc39/proposal-decorators