前言
js 和 ts 中经常看到@
函数名
的字样这个就是装饰器。它可以修饰类,类的属性,类的原型上的方法,说的简单一点它就是一个函数,可以传递参数在修饰的时候把这个类的属性传递给修饰的函数。
@flag("帅")
class Animal{
@readOnly
age = 18
constructor(){
this.name = '小丑'
}
@before
address(){
console.log(this);
console.log("小丑的小屋");
}
}
配置环境
装饰器还不被浏览器解析,需要通过babel
来转化之后才行。
我们需要借助@babel/cli[1]来编译文件
安装@babel/cli
最好是安装到本地项目中,通过npx
来启动babel
去编译,不要全局安装@babel/cli
到本机上,会有不同版本babel
的问题,被坑哭了
npx
是node
提供的,可以帮助我们执行.bin
目录下的文件
需要安装的插件
代码语言:javascript复制npm install @babel/core @babel/cli -D
npm install @babel/preset-env -D
npm install @babel/plugin-proposal-class-properties -D 主要作用是用来转化类的属性的
npm install @babel/plugin-proposal-decorators -D
需要配置的文件.babelrc
{
"presets":[ //预设包
"@babel/preset-env"
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
编译命令
代码语言:javascript复制npx babel xxx.js -o xxx.js
修饰类的静态属性
代码语言:javascript复制function flag(){
console.log(arguments);
}
代码语言:javascript复制function flag(custructor){
custructor.type="帅"
}
console.log(Animal.type) //❌这个写法是错误的
编译后的 es5
代码语言:javascript复制"use strict";
var _dec, _class, _temp;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i ) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
var Animal =
((_dec = flag()),
_dec(
(_class =
((_temp = /*#__PURE__*/ (function () {
function Animal() {
_classCallCheck(this, Animal);
this.age = 18;
this.name = "小丑";
}
_createClass(Animal, [
{
key: "address",
value: function address() {
console.log(this);
console.log("小丑的小屋");
},
},
]);
return Animal;
})()),
_temp))
) || _class);
function flag(custructor) {
custructor.type = "帅";
}
console.log(Animal.type);
抽取代码之后是一个自执行函数,传入返回的构造函数之后执行
装饰器函数可以改造为:
代码语言:javascript复制function flag(value){
return function(custructor){
custructor.type = value
}
}
console.log(Animal.type); //✔ 帅
修改类的属性(实例上的属性)
代码语言:javascript复制function readOnly(target,prototype,descriptor){
console.log(arguments)
descriptor.writable = false;
console.log(arguments);
setTimeout(()=>{
console.log(target == Animal.prototype); //类的原型
console.log(Animal.prototype); //{constructor: ƒ, address: ƒ}
console.log(Animal.prototype.constructor);
})
}
let a= new Animal();
console.log(a.age) //18
代码语言:javascript复制a.age =19
console.log(a.age) //❌ read only
修改原型上的方法
代码语言:javascript复制function before(target,prototype,descriptor){
console.log(arguments)
let oldSay = descriptor.value;
descriptor.value = function(){
console.log('before');
console.log(...arguments);
oldSay.call(target,...arguments)
}
//console.log(descriptor);
}
let a= new Animal();
a.address() //小丑的小屋
执行结果:
参考资料
[1]babel-cli: https://www.babeljs.cn/docs/babel-cli