es6es7之Decorator装饰器

8次阅读

共计 1849 个字符,预计需要花费 5 分钟才能阅读完成。

@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;
}

被装饰的对象可以使用多个装饰器。

正文完
 0