简介
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文件了。
语法
作用于类的装饰器
简单的类装饰器
类的装饰器函数的第一个参数,就是所有装饰的目标类,如下:
@flagclass 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。```javascriptclass Animal {@readonlyPI = 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>'
