📜  如何在 TypeScript 中使用属性装饰器?

📅  最后修改于: 2022-05-13 01:56:13.537000             🧑  作者: Mango

如何在 TypeScript 中使用属性装饰器?

装饰器是一种用所需值和功能包装现有代码的方法,以创建它的新修改版本。目前,它仅支持一个类及其组件,如下所述:

  • 类本身
  • 类方法
  • 类属性
  • 类的对象访问器(Getter 和 Setter)
  • 类方法的参数

注意:目前,装饰器处于 JavaScript 的第 2 阶段提案中,可作为 TypeScript 的实验性功能使用。要启用对装饰器的实验性支持,您必须在命令行或 tsconfig.json 中启用experimentalDecorators 编译器选项

句法:

@(argument)
// code of component ...

示例:举个例子,我们有一个 Greeter 类,它有两个属性 firstMessage 和 secondMessage,我们将登录到控制台。我们将使用装饰器通过添加参数中提供的发件人名称来修改 firstMessage 属性。请参阅下面的课程:

Javascript
class Greeter {
    @ModifyMessage('gfg')
    first_message: string;
    second_message: string;
}


Javascript
function ModifyMessage(sender: string) {
    return function (target: any, propertyKey: string) {
        // use  sender, target and propertyKey arguments ...
    }
}


Javascript
function ModifyMessage(sender: string) {
  
    return function (target: any, propertyKey: string) {
        let modifiedMessage: string;
  
        // Return modifiedMessage whenever the message is asked
        const getter = function () {
            return modifiedMessage;
        };
  
        // Set the modifiedMessage value
        const setter = function () {
            modifiedMessage = `Hello from ${sender}!`;
        };
    }
}


Javascript
function ModifyMessage(sender: string) 
  
    return function (target: any, propertyKey: string) {
  
        let modifiedMessage: string;
  
        // Return modifiedMessage whenever the message is asked
        const getter = function () {
            return modifiedMessage;
        };
  
        // Set the modifiedMessage value
        const setter = function () {
            modifiedMessage = `Hello from ${sender}!`;
        };
  
        // Overwrite the original message with 
        // modifiedMessage we just created
        Object.defineProperty(target, propertyKey, {
            get: getter,
            set: setter
        });
    }
}


Javascript
function ModifyMessage(sender: string) {
  
    return function(target: any, propertyKey: string) {
      
        let modifiedMessage : string;
          
        // Return modifiedMessage whenever the message is asked
        const getter = function() {
            return modifiedMessage;
        };
          
        // Set the modifiedMessage value
        const setter = function() {
            modifiedMessage = `Hello from ${sender}!`;  
        }; 
  
        // Overwrite the original message with
        // modifiedMessage we just created
        Object.defineProperty(target, propertyKey, {
            get: getter,
            set: setter
        });
    }
}
  
class Greeter {
      
     // Modify message property using decorator
    @ModifyMessage("gfg")
    firstMessage: string;
  
    secondMessage: string;
   
    constructor() {
        this.firstMessage = "Hi there!";
        this.secondMessage = "Hi there!";
    }
  
    greet() {
        console.log(`first message: ${this.firstMessage}`);
        console.log(`second message: ${this.secondMessage}`);
    }
}
  
let myGreeter = new Greeter();
myGreeter.greet();


在这里,我们为 Greeter 类的 firstMessage 属性使用了修饰器 ModifyMessage。它将在运行时使用提供的参数调用 ModifyMessage函数。它应该返回一个函数,在这个函数中我们可以使用 firstMessage 属性。请参阅下面的此函数:

Javascript

function ModifyMessage(sender: string) {
    return function (target: any, propertyKey: string) {
        // use  sender, target and propertyKey arguments ...
    }
}

我们返回的函数有两个参数:

  1. 目标:如果我们在静态成员上使用装饰器,则为类的构造函数;如果在实例成员上使用装饰器,则为类的原型。在我们的例子中,firstMessage 是一个实例成员,因此目标将引用 Greeter 类的原型。
  2. propertyKey:它是属性的名称。

让我们在 ModifyMessage函数。当我们想要获取 firstMessage 或将 firstMessage 设置为新值时,将触发这些函数。请看下面的代码:

Javascript

function ModifyMessage(sender: string) {
  
    return function (target: any, propertyKey: string) {
        let modifiedMessage: string;
  
        // Return modifiedMessage whenever the message is asked
        const getter = function () {
            return modifiedMessage;
        };
  
        // Set the modifiedMessage value
        const setter = function () {
            modifiedMessage = `Hello from ${sender}!`;
        };
    }
}

最后,我们将使用 Object.defineProperty函数。它用于将给定属性添加到对象。它需要三个参数:

  1. 对象实例:我们要为其添加属性的对象。在我们的例子中,Greeter Class 实例存储在目标变量中。
  2. propertyName:属性的名称
  3. 配置对象:它是一个具有属性规范的对象。在我们的例子中,我们将添加 getter 和 setter函数作为规范。

我们将使用这个函数用我们的 modifiedMessage 覆盖现有的 firstMessage 属性。请看下面的代码:

Javascript

function ModifyMessage(sender: string) 
  
    return function (target: any, propertyKey: string) {
  
        let modifiedMessage: string;
  
        // Return modifiedMessage whenever the message is asked
        const getter = function () {
            return modifiedMessage;
        };
  
        // Set the modifiedMessage value
        const setter = function () {
            modifiedMessage = `Hello from ${sender}!`;
        };
  
        // Overwrite the original message with 
        // modifiedMessage we just created
        Object.defineProperty(target, propertyKey, {
            get: getter,
            set: setter
        });
    }
}

现在我们准备好使用装饰器了。请参阅下面的完整代码:

Javascript

function ModifyMessage(sender: string) {
  
    return function(target: any, propertyKey: string) {
      
        let modifiedMessage : string;
          
        // Return modifiedMessage whenever the message is asked
        const getter = function() {
            return modifiedMessage;
        };
          
        // Set the modifiedMessage value
        const setter = function() {
            modifiedMessage = `Hello from ${sender}!`;  
        }; 
  
        // Overwrite the original message with
        // modifiedMessage we just created
        Object.defineProperty(target, propertyKey, {
            get: getter,
            set: setter
        });
    }
}
  
class Greeter {
      
     // Modify message property using decorator
    @ModifyMessage("gfg")
    firstMessage: string;
  
    secondMessage: string;
   
    constructor() {
        this.firstMessage = "Hi there!";
        this.secondMessage = "Hi there!";
    }
  
    greet() {
        console.log(`first message: ${this.firstMessage}`);
        console.log(`second message: ${this.secondMessage}`);
    }
}
  
let myGreeter = new Greeter();
myGreeter.greet();

输出:

first message: Hello from gfg!
second message: Hi there!

结论:因此,我们看到我们可以在类的属性上使用装饰器并对其进行操作。装饰器帮助我们创建更具可读性和灵活性的代码。