# 前言
js和ts中经常看到@
+函数名的字样这个就是装饰器。它可以修饰类,类的属性,类的原型上的方法,说的简单一点它就是一个函数,可以传递参数在修饰的时候把这个类的属性传递给修饰的函数。
@flag("帅")
class Animal{
@readOnly
age = 18
constructor(){
this.name = '小丑'
}
@before
address(){
console.log(this);
console.log("小丑的小屋");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 配置环境
装饰器还不被浏览器解析,需要通过babel来转化之后才行
我们需要借助@babel/cli来编译文件
安装@babel/cli最好是安装到本地项目中,通过npx来启动babel去编译,不要全局安装@babel/cli到本机上,会有不同版本babel的问题,被坑哭了~
npx是node提供的,可以帮助我们执行.bin目录下的文件
需要安装的插件
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
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
需要配置的文件.babelrc
{
"presets":[ //预设包
"@babel/preset-env"
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
编译命令
npx babel xxx.js -o xxx.js
1
# 修饰类的静态属性
function flag(){
console.log(arguments);
}
1
2
3
2
3
function flag(custructor){
custructor.type="帅"
}
console.log(Animal.type) //❌这个写法是错误的
1
2
3
4
2
3
4
编译后的es5
"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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
抽取代码之后是一个自执行函数,传入返回的构造函数之后执行
装饰器函数可以改造为
function flag(value){
return function(custructor){
custructor.type = value
}
}
console.log(Animal.type); //✔ 帅
1
2
3
4
5
6
2
3
4
5
6
# 修改类的属性(实例上的属性)
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
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
a.age =19
console.log(a.age) //❌ read only
1
2
2
# 修改原型上的方法
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
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
执行结果