@Decorator 装饰器是es7的语法,这个方法对于面向切面编程有了更好的诠释,在一些情境中可以使用,比如路人A的代码实现了一需求,路人B希望用A的方法来实现一个新的需求,而路人A又不希望大改自己的代码,这时候装饰器就能派上用场了。本文就结合情境来说说Decorator的用法。
装饰器顾名思义就是装饰某种东西的方法,可以用来装饰属性、变量、函数、类、实例方法... 本质上是个函数。以@符开头,函数名称自拟。
先看这么一个类↓
@hobby
Class Person {
constructor() {
}
@readOnly
name = 'AAA';
@dealData
eat() {
console.log('爱吃苹果')
}
}
let oP = new Person();
这个函数就用来修饰装饰对象的
function readOnly(proto, key, descriptor) {
console.log(proto, key, descriptor) //原型, 'name ', 一个包含对name属性描述内容的对象
}
descriptor是重头戏,这个对象里包含对装饰对象的描述属性
configurable: true/false, 可配置与否
enumerable: true/false, 可枚举与否
writable: true/false, 可写与否
initializer: 静态属性的value值
value: 非静态属性的value值
上面三个属性好理解,修改也方便,如下
function readOnly(proto, key, descriptor) {
// 将静态属性name改为只可读,不可写
descriptor.writable = false;
}
initializer: 静态属性的value值
value: 非静态属性的value值
这两个值就比较有意思了,他们俩的关系是水火不容的,静态属性的装饰器的descriptor里有initializer, 而非静态属性的装饰器其descriptor对象里则是有value这个属性,没有initializer。
function readOnly(proto, key, descriptor) {
// initializer可以重新赋值
descriptor.initializer = function () {
// 函数返回的值就是该静态属性新的值
return 'BBB'
}
}
function dealData(proto, key, descriptor) {
// 当我们需要改变函数功能的时候,可以通过这种方式,相当于做个代理,也不会影响原函数
// 存一下原来的方法
let oldValue = descriptor.value;
// 修改(添加)函数的原有功能
descriptor.value = function() {
console.log('爱吃橘子');
oldValue.call(this, arguments);
}
}
装饰器也是可以传参并且执行返回的函数的
Class Person {
constructor() {
}
@readOnly
name = 'AAA';
@dealData('AAA')
eat() {
console.log('爱吃苹果')
}
}
function dealData(who) {
return function (proto, key, descriptor) {
let oldValue = descriptor.value;
descriptor.value = function() {
console.log(who + '爱吃橘子'); // AAA爱吃橘子
return oldValue.call(this, arguments);
}
}
}
值得注意的一点是如果这里的eat函数写成箭头函数赋值的形式,就不再是原型上的方法了而是变为静态属性了,要注意一下。
Class Person {
constructor() {
}
@readOnly
name = 'AAA';
@dealData('AAA')
eat = ()=> {
console.log('爱吃苹果')
}
}
装饰器装饰类:
@hobby
Class Person {
constructor() {
}
@readOnly
name = 'AAA';
@dealData
eat() {
console.log('爱吃苹果')
}
}
function hobby(target) {
console.log(target) // 结果是这个类本身
// 就可以通过target修改类的属性
target.name = 'CCC';
// 增加属性
target.age = 18;
}
被装饰的对象可以使用多个装饰器。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。