es7装饰器基础描述

1,262 阅读3分钟

导读:这是在学习ts时,对es7中装饰器的学习,所以用到一些ts语法。

装饰器是什么

在学习一个知识前,得先了解它,它是什么,它有什么用。

装饰器是一种特殊的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。

通俗讲,装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。

我对装饰器分类是这样的:
    装饰器:类装饰器、属性装饰器、方法装饰器、方法参数装饰器
    类装饰器:普通饰器(无参数传递)
            装饰器工厂(有参数传递)

类装饰器

普通装饰器

function decoratorHttp(target: any) {
    console.log(target, 'HttpClient 构造函数');
    target.prototype.url = 'https://juejin.cn';
}

@decoratorHttp  // 注意这里别加 ; (分号)
class HttpClient {
    constructor() {
        
    }
    getData() {
        
    }
}

let httpC: any = new HttpClient();
console.log(httpC.url); // https://juejin.cn

装饰器工厂

function decoratorHttp(params: string) {
    return function(target: any) {
        console.log(params, '参数'); // xxx 参数
        console.log(target, 'HttpClient 构造函数');
        target.prototype.url = 'https://juejin.cn';
    }
}

@decoratorHttp('xxx')
class HttpClient {
    constructor() {
        
    }
    getData() {
        
    }
}

let httpC: any = new HttpClient();
console.log(httpC.url); // https://juejin.cn

属性装饰器

function decoratorAttr (params: string) {
    return function(target: any, attrName: string) {
        console.log(params, '参数');
        // 对于 static 静态成员来说,target 是构造函数
        // 对于 public 实例成员来说,target 是原型对象
        console.log(target, 'HttpClient');
        console.log(attrName, '属性名'); // url 属性名
        // 可以修改属性
        target[attrName] = 'www.bilibili.com';
    }
}

class HttpClient {
    @decoratorAttr('public');
    public url: string | undefined;
    @decoratorAttr('static');
    static url: string | undefined;
    constructor() {
        
    }
    getData() {
        console.log(this.url);
    }
}

let httpC = new HttpClient();
httpC.getData(); // www.bilibili.com

方法装饰器

function decoratorMethod(params: string) {
    return function(target: any, methodName: string, desc: any) {
        console.log(params, '参数');
        console.log(target, '原型对象');
        console.log(methodName, '函数名');
        console.log(desc, '描述对象');
        console.log(desc.value, '方法');

        let methodLoad = desc.value;
        desc.value = function(...arg: Array<any>) {
            methodLoad.apply(this, arg); // 这里继承原来的方法
            // 可以修改方法
            arg = arg && arg.map((item: any) => {
                return String(item);
            })
            console.log(arg, 'decorator---arg'); // ["123", "xxx"] "decorator---arg"
        }
    }
}

class HttpClient {
    public url: string | undefined;
    constructor() {

    }
    @decoratorMethod('xxx')
    getData(...arg: Array<any>) {
        console.log(arg, 'HttpClient---arg'); // [123, "xxx"] "HttpClient---arg"
    }
}

let httpC = new HttpClient();
httpC.getData(123, 'xxx');

方法参数装饰器

function decoratorParam(params: string) {
    return function(target: any, methodName: string, paramIndex: number) {
        console.log(params, '参数');
        console.log(target, '原型对象');
        console.log(methodName, '函数名');
        console.log(paramIndex, '参数下标');
        // 可以操作属性
        target.url = 'www.bilibili.com';
    }
}

class  HttpClient {
    public url: string | undefined;
    constructor(){

    }
    getData(@decoratorParam('xxx') info: string) {
        console.log(info + this.url);
    }
}

let httpC = new HttpClient();
httpC.getData('url: ');

类修饰器、属性修饰器、方法修饰器、方法参数修饰器执行时机

function _classDecorator1 (params1: any) {
    return function(target: any) {
        console.log(params1 + '类装饰器1');
    }
}
function _classDecorator2(params2: any) {
    return function(target: any) {
        console.log(params2 + '类装饰器2');
    }
}
function _attributeDecorator1(params: any) {
    return function(target: any, attrName: any) {
        console.log(params, '属性装饰器1');
    }
}
function _methodDecorator1(params: any) {
    return function(target: any, methodName: any, desc: any) {
        console.log(params, '方法装饰器1');
    }
}
function _methodDecorator2(params: any) {
    return function(target: any, methodName: any, desc: any) {
        console.log(params, '方法装饰器2');
    }
}
function _methodParamsDecorator1(params: any) {
    return function(target: any, methodName: any, paramsIndex: number) {
        console.log(params, '方法参数装饰器1');
    }
}
function _methodParamsDecorator2(params: any) {
    return function(target: any, methodName: any, paramsIndex: number) {
        console.log(params, '方法参数装饰器2');
    }
}

@_classDecorator1('_classDecorator1')
@_classDecorator2('_classDecorator2')
class HttpClient {
    constructor() {
        
    }

    @_methodDecorator1('_methodDecorator1')
    @_methodDecorator2('_methodDecorator2')
    getData(@_methodParamsDecorator1('_methodParamsDecorator1') uin: string, @_methodParamsDecorator2('_methodParamsDecorator2') info: string) {
        console.log('getData');
    }

    @_attributeDecorator1('_attributeDecorator1')
    public url: string | undefined;

    setData(@_methodParamsDecorator1('_methodParamsDecorator1') uin: string, @_methodParamsDecorator2('_methodParamsDecorator2') info: string) {
        console.log('setData');
    }
}
/*
_methodParamsDecorator2 方法参数装饰器2
 _methodParamsDecorator1 方法参数装饰器1
 _methodDecorator2 方法装饰器2
 _methodDecorator1 方法装饰器1
 _attributeDecorator1 属性装饰器1
 _methodParamsDecorator2 方法参数装饰器2
 _methodParamsDecorator1 方法参数装饰器1
 _classDecorator2类装饰器2
 _classDecorator1类装饰器1
*/
总结下:
    从上向下执行修饰器
    在方法中: 方法参数修饰器
                方法修饰器
    最后执行类修饰器
    有多个时,后写的先执行