0%

JavaScript装饰器

JS装饰器是ES7的新语法,浏览器,nodejs不一定支持,需要babel转译。

实验环境

创建一个目录test,结构为:

1
2
3
4
5
6
7
.
├── .babelrc
├── .npmrc
├── lib
├── package.json
└── src
└── index.js

babel的装饰器配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# .babelrc
{
"presets": [
"@babel/preset-env"
],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"@babel/plugin-proposal-class-properties"
]
}

依赖包与测试命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# package.json
{
"name": "testmobx",
"version": "1.0.0",
"description": "testmobx",
"main": "index.js",
"directories": {
"lib": "lib"
},
"scripts": {
"build": "babel src -d lib",
"test": "node lib/index.js"
},
"author": "jason",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.15.5",
"@babel/cli": "^7.15.0",
"@babel/plugin-proposal-class-properties": "^7.14.5",
"@babel/plugin-proposal-decorators": "^7.15.4",
"@babel/preset-env": "^7.15.6"
}
}

npm源:

1
2
# .npmrc
registry=https://registry.npm.taobao.org

安装依赖包:

1
2
cd test
yarn

测试代码

源码都在 src/index.js 中。js装饰器可以装饰的对象:类、属性、方法。

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
60
61
62
63
// 装饰器:
// 装饰属性(或方法)时:
// target为属性的类对象,key为属性名字符串,descriptor为属性key的属性描述符对象
// 装饰类时:
// target为类,key与descriptor都是undefined

function readOnly(target, key, descriptor) {
console.log('target:', target, typeof target);
console.log('key:', key, typeof key);
console.log('desc:', descriptor, typeof descriptor);
if (typeof key === 'string') { // 作为属性或方法装饰器时,key为字符串
if (typeof descriptor.value === 'function') { // 作为方法装饰器
console.log('~~~ decorator of method');
return descriptor.value;
} else { // 作为属性装饰器
return {
...descriptor,
writable: false // 覆盖为false
}
}
} else { // 作为类装饰器
console.log('~~~ decorator of cls');
return target;
}
}

class Oatmeal {
@readOnly viscosity = 20; // 属性装饰器
constructor(flavor) {
this.flavor = flavor;
}
}

var oatmeal = new Oatmeal('Brown Sugar Cinnamon');
// oatmeal.viscosity = 30; // 已设为只读,修改将报错
console.log(oatmeal);

console.log('\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~');

@readOnly
class A {
constructor() {
this.a = 111;
}
};

var a = new A();
console.log(a.a);

console.log('\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~');

class B {
constructor() {
this.b = 222;
}
@readOnly
show() {
console.log(this.b);
}
}

var b = new B();
b.show();

执行结果

其中initializer与babel相关,当装饰器给属性装饰时,属性描述符对象中会有initializer,为函数,执行descriptor.initializer()后将返回属性的值20。

js-decor1

参考:
https://segmentfault.com/a/1190000021593373