简介
JS 装饰器(Decorator) Decorator 是ES7 的一个新语法,目前仍处于第2阶段提案中。
装饰器可以修饰类、类的属性、类的原型上的方法,修饰的时候 就是把这个类,属性、方法 … 传递给修饰的函数。
环境配置
浏览器无法识别 decorator 语法,需要用 babel 转化为 ES5 语法。
安装Babel
npm install @babel/cli @babel/core @babel/preset-env
@babel/core 包含了 Babel的核心功能。
@babel/cli 是一个能从终端(命令行)使用的工具。
@babel/preset-env 可以智能的判断语言的版本并把它转化成 ES5 语法
安装 decorator 插件
npm install --save-dev @babel/plugin-proposal-decorators
配置文件
在运行目录下添加一个 .babelrc 文件,配置预设包 和 插件,如下:
{
"presets": [
"@babel/preset-env"
],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
[
"@babel/plugin-proposal-class-properties"
]
]
}
2022更新 @babel/plugin-proposal-class-properties 已经被包裹在@babel/preset-env 中,不需要额外配置。
运行
npx babel 2.class.decorator.js -o es5.js -w
//得到结果,在同目录下生成一个 es5.js 文件,同时 -w 监听这个文件变动
生成之后就可以直接运行这个es5.js文件了。
语法
作用于类的装饰器
简单的类装饰器
类的装饰器函数的第一个参数,就是所有装饰的目标类,如下:
@flag
class Animal {}
//装饰器函数
function flag(target) {
target.type = '哺乳类'
}
console.log(Animal.type);//哺乳类
给类装饰器传参数
@flag('装饰器参数')
class Animal {}
//装饰器函数
function flag(param) {
console.log(param);//装饰器参数
return function(constructor){
constructor.type = '哺乳类'
}
}
console.log(Animal.type);//哺乳类
作用于方法的类装饰器
方法的装饰器函数拥有三个参数:
- target 构造函数的原型对象
- property 属性名
- descriptor 属性名描述符 value、enumerable、configurable、writable,没有get、set
```javascript
class Animal {
PI = 3.14;
name = ‘xxx’; //实例上的属性 并不是原型上的属性
@before
say(a, b, c) {
} a() {console.log('说话', a, b, c, this.a)
} }return 1;
let animal = new Animal();
//利用装饰器函数创建一个aop函数(面向切片编程)。 function before(target, property, descriptor) { //因为执行before时,构造函数尚未创建完成,所以这边异步获取。 setTimeout(()=>{ console.log(target === Animal.prototype);//true console.log(property);//say console.log(descriptor);//{value: [Function: say],writable: true,enumerable: false,configurable: true} },100)
//函数装饰器(保留原有功能不变,添加新的逻辑)
let oldSay = descriptor.value;
descriptor.value = function (...args) {
console.log('before');
oldSay(...args);
console.log('after');
}
} animal.say(1, 2, 3);
<a name="aLZ83"></a>
### 作用于属性的类装饰器(ES7)
在 ES6 中,装饰器不支持装饰属性,在ES7中才添加进来。<br />同样拥有三个参数:
- target 构造函数的原型对象
- property 属性名
- descriptor 属性名描述符 value、enumerable、configurable、writable,没有get、set。
```javascript
class Animal {
@readonly
PI = 3.14;
name = 'xxx'; //实例上的属性 并不是原型上的属性
say(a, b, c) {
console.log('说话', a, b, c, this.a)
}
a() {
return 1;
}
}
function readonly(target, property, descriptor) {
descriptor.writable = false;
// setTimeout(() => {
// console.log(target === Animal.prototype);
// console.log(arguments)
// })
}
let animal = new Animal();
animal.PI = 3.15;//TypeError: Cannot assign to read only property 'PI' of object '#<Animal>'