微信公众号
扫描关注微信公众号

什么是装饰器(Decorator)?

原创 来源:博客站 阅读 0 03月17日 23:39 听全文 分类:Typescript系列

装饰器(Decorator)是 TypeScript 中的一种特殊语法,用于修饰类、方法、属性或参数。装饰器本质上是一个函数,它可以在运行时修改或扩展被装饰对象的行为。装饰器通常用于实现横切关注点(如日志记录、权限检查、性能监控等),而不会侵入被装饰对象的代码。

装饰器的基本语法

装饰器使用 @ 符号来应用,后面跟着一个装饰器函数。装饰器函数会在运行时被调用,并接收被装饰对象的元数据作为参数。

装饰器的类型

TypeScript 支持以下几种装饰器:

  1. 类装饰器:应用于类的构造函数。
  2. 方法装饰器:应用于类的方法。
  3. 属性装饰器:应用于类的属性。
  4. 参数装饰器:应用于类方法的参数。
  5. 访问器装饰器:应用于类的访问器(getter/setter)。

示例

1. 类装饰器

以下是一个简单的类装饰器示例,它会在类实例化时打印日志:

function logClass(target: Function) {
    console.log(`Class ${target.name} is instantiated.`);
}

@logClass
class MyClass {
    constructor() {
        console.log("MyClass instance created.");
    }
}

const instance = new MyClass();
// 输出:
// Class MyClass is instantiated.
// MyClass instance created.

在这个例子中,logClass 是一个类装饰器,它会在 MyClass 实例化时打印日志。

2. 方法装饰器

以下是一个方法装饰器示例,它会在方法调用时打印日志:

function logMethod(target: any, key: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function(...args: any[]) {
        console.log(`Method ${key} is called with arguments: ${JSON.stringify(args)}`);
        const result = originalMethod.apply(this, args);
        console.log(`Method ${key} returned: ${result}`);
        return result;
    };

    return descriptor;
}

class MyClass {
    @logMethod
    greet(name: string): string {
        return `Hello, ${name}!`;
    }
}

const instance = new MyClass();
instance.greet("Alice");
// 输出:
// Method greet is called with arguments: ["Alice"]
// Method greet returned: Hello, Alice!

在这个例子中,logMethod 是一个方法装饰器,它会在 greet 方法调用时打印日志。

3. 属性装饰器

以下是一个属性装饰器示例,它会在属性定义时打印日志:

function logProperty(target: any, key: string) {
    let value = target[key];

    const getter = function() {
        console.log(`Getting value of property ${key}: ${value}`);
        return value;
    };

    const setter = function(newVal: any) {
        console.log(`Setting value of property ${key} to: ${newVal}`);
        value = newVal;
    };

    Object.defineProperty(target, key, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true
    });
}

class MyClass {
    @logProperty
    name: string;

    constructor(name: string) {
        this.name = name;
    }
}

const instance = new MyClass("Alice");
instance.name = "Bob";
console.log(instance.name);
// 输出:
// Setting value of property name to: Alice
// Setting value of property name to: Bob
// Getting value of property name: Bob
// Bob

在这个例子中,logProperty 是一个属性装饰器,它会在 name 属性被访问或修改时打印日志。

4. 参数装饰器

以下是一个参数装饰器示例,它会在方法参数定义时打印日志:

function logParameter(target: any, key: string, parameterIndex: number) {
    console.log(`Parameter ${parameterIndex} of method ${key} is decorated.`);
}

class MyClass {
    greet(@logParameter name: string): string {
        return `Hello, ${name}!`;
    }
}

const instance = new MyClass();
instance.greet("Alice");
// 输出:
// Parameter 0 of method greet is decorated.

在这个例子中,logParameter 是一个参数装饰器,它会在 greet 方法的参数定义时打印日志。

5. 访问器装饰器

以下是一个访问器装饰器示例,它会在访问器被调用时打印日志:

function logAccessor(target: any, key: string, descriptor: PropertyDescriptor) {
    const originalGet = descriptor.get;
    const originalSet = descriptor.set;

    if (originalGet) {
        descriptor.get = function() {
            console.log(`Getting value of accessor ${key}`);
            return originalGet.apply(this);
        };
    }

    if (originalSet) {
        descriptor.set = function(value: any) {
            console.log(`Setting value of accessor ${key} to: ${value}`);
            originalSet.apply(this, [value]);
        };
    }

    return descriptor;
}

class MyClass {
    private _name: string;

    @logAccessor
    get name(): string {
        return this._name;
    }

    set name(value: string) {
        this._name = value;
    }
}

const instance = new MyClass();
instance.name = "Alice";
console.log(instance.name);
// 输出:
// Setting value of accessor name to: Alice
// Getting value of accessor name
// Alice

在这个例子中,logAccessor 是一个访问器装饰器,它会在 name 访问器被调用时打印日志。

装饰器的执行顺序

当多个装饰器应用于同一个目标时,它们的执行顺序如下:

  1. 参数装饰器:按照参数定义的顺序执行。
  2. 方法装饰器:按照方法定义的顺序执行。
  3. 访问器装饰器:按照访问器定义的顺序执行。
  4. 属性装饰器:按照属性定义的顺序执行。
  5. 类装饰器:按照类定义的顺序执行。

总结

装饰器是 TypeScript 中用于修饰类、方法、属性或参数的特殊语法。通过装饰器,你可以在运行时修改或扩展被装饰对象的行为,而不会侵入被装饰对象的代码。装饰器通常用于实现横切关注点,如日志记录、权限检查、性能监控等。理解装饰器的使用场景和语法,可以帮助你编写出更灵活、更可维护的代码。

- - - - - - - 剩余部分未读 - - - - - - -
扫描关注微信公众号获取验证码,阅读全文
你也可以查看我的公众号文章,阅读全文
你还可以登录,阅读全文
内容由AI生成仅供参考和学习交流,请勿使用于商业用途。
出处地址:http://www.07sucai.com/tech/697.html,如若转载请注明原文及出处。
版权声明:本文来源地址若非本站均为转载,若侵害到您的权利,请及时联系我们,我们会在第一时间进行处理。