typescript 装饰器实践-TypeScript 装饰器定义

2024-04-29 0 2,985 百度已收录

TypeScript 装饰定义

更新时间:2021年12月10日 09:42:26 作者:周一万

本文主要介绍TypeScript装饰器的定义。 装饰器是一种新的声明,可以应用于类声明、方法访问器、属性参数。 我们来看看TypeScript装饰器的具体定义。 ,有需要的同学可以参考一下,希望对你有帮助

目录 2. 类装饰器 3. 方法装饰器 4. 访问器装饰器 5. 属性装饰器 6. 参数装饰器

前言:

ECMAScript中已提出Decorator,但尚未最终确定; 它已经在 TypeScript 中实现,但它仍然是一个实验功能。 如果你想使用装饰器,你需要在 tsconfig.json 属性中添加experimentalDecorators,并将其设置为true

1. 概念

1.1 定义

装饰器是一种新的声明,可以作用于类声明、方法、访问器、属性和参数。 装饰器的使用使用@符号函数名,如@testDecorator。 其中,testDecorator必须是一个函数或者返回一个函数。 该函数在运行调用,并且将修饰声明作为参数手动传入。 。

值得注意的是,装饰器必须放在要装饰的内容的正上方,并且所有装饰器都不能在声明文件.d.ts中使用。 或在任何外部上下文中(例如声明)。

装饰器的定义和使用如下:

// 定义一个函数作为装饰器函数使用
function testDecorator() {}
// 通过@符号使用装饰器
@testDecorator

1.2 装饰鞋厂

所谓装饰鞋厂也是一种功能。 与普通装饰器函数不同的是,它的返回值是一个函数,返回的函数作为装饰器调用的函数。 如果使用装饰器鞋工厂,使用时可以根据当前使用情况传递不同的参数,但是使用时需要添加函数调用

示例代码如下:

// 装饰器工厂,返回值是一个函数
function testDecorator() {
    return function() {}
}
// 通过@符号 + 函数调用的方式使用装饰器
@testDecorator()

1.3 装饰器组合使用

装饰器可以组合使用,这意味着您可以使用一个目标引用多个装饰器。

示例代码如下所示

// 定义两个装饰器函数
function setName() {}
function setAge() {}
// 使用装饰器
@setName
@setAge
class Person {}

如果使用多个装饰器,则装饰器按顺序执行,执行顺序如下:

如果使用普通的装饰器函数,执行顺序是从下到上。

示例代码如下:

function setName(constructor: any) {
  console.log('setName', constructor)
}
function setAge(constructor: any) {
  console.log('setAge', constructor)
}
@setName
@setAge
class Person {}
/* 执行结果如下:
setAge [Function: Person]
setName [Function: Person]
*/

如果是装饰器鞋工厂,它的执行顺序是先从上到下执行鞋工厂函数,再从下到上执行鞋工厂函数返回函数。示例代码如下

function setName() {
  console.log('get setName')
  return function (constructor: any) {
    console.log('setName', constructor)
  }
}
function setAge() {
  console.log('get setAge')
  return function (constructor: any) {
    console.log('setAge', constructor)
  }
}
@setName()
@setAge()
class Person {}
/* 执行结果如下:
get setName
get setAge
setAge [Function: Person]
setName [Function: Person]
*/

1.4 装饰器评估

类定义中不同声明上的装饰器将按以下顺序引用:

2. 类装饰器

类装饰器用在类声明之前,并且必须靠近需要装饰的内容。 类装饰器应用于类声明。

类装饰器表达式将在运行时作为函数调用。 它有一个参数typescript 装饰器实践,即该类的构造函数

示例代码如下:

let sign = null
function setName() {
  return function (constructor: Function) {
    sign = constructor
  }
}
@setName()
class Info {
  constructor() {}
}
console.log(sign === Info) // true
console.log(sign === Info.prototype.constructor) // true

从上面的代码可以看到,Info类的prototype对象的constructor属性指向Info本身。

我们还可以通过装饰器来改变类的原型对象和构造函数。 示例代码如下:

// * 通过装饰器 修改原型对象与构造函数
function addName(constructor: { new (): any }) {
  constructor.prototype.name = '一碗周'
}
@addName
class Person {}
const person = new Person()
console.log(person.name) // error 类型“A”上不存在属性“name”

前面的代码中,我们通过addName修饰符给Person类的原型添加了name属性,这样通过Person类实例化的对象就可以访问到name属性了。 然而typescript 装饰器实践实际情况并非如此。 已经被扔到这里了。 如果出现异常,可以通过类型断言解决这个问题,也可以定义一个同名socket并声明一个merge来解决这个问题。

示例代码如下:

function addName(constructor: { new (): any }) {
  constructor.prototype.name = '一碗周'
}
@addName
class Person {}
const person = new Person()
// 1. 类型断言
// console.log((person as any).name) // 一碗周
// 2. 定义同名接口,声明合并
interface Person {
  name: string
}
console.log(person.name) // 一碗周

而且我们还可以通过装饰器重载构造函数。 示例代码如下:

// * 重载构造函数
function classDecorator(
  constructor: T,
) {
  return class extends constructor {
    name = '一碗周'
    hobby = 'coding'
  }
}
@classDecorator
class Person {
  age = 18
  name: string
  constructor(name: string) {
    this.name = name
  }
}
const person = new Person('一碗周')
console.log(person)
/* 执行结果如下:
{
  age: 18,
  name: '一碗周',
  hobby: 'coding',
}
*/

我们还可以以装饰鞋工厂的形式传递参数。 示例代码如下:

// 定义一个装饰器工厂
function classDecorator(_name: string) {
  return function (constructor: T) {
    return class extends constructor {
      name = _name
      hobby = 'coding'
    }
  }
}
@classDecorator('一碗周')
class Person {
  age = 18
  name: string
  constructor(name: string) {
    this.name = name
  }
}
const person = new Person('一碗粥')
console.log(person)
/* 执行结果如下:
{
  age: 18,
  name: '一碗周',
  hobby: 'coding',
}
*/

3.方法装饰器

方法装饰器用于处理类中的方法。 它可以处理方法的属性描述符(详细信息请参阅属性描述符),也可以处理方法定义。 方法装饰器在运行时也被称为函数,它包含三个参数。

详情如下所示:

对于静态成员,它是类的构造函数,对于实例成员,它是类的原型对象。

会员姓名

成员的属性描述符。

值得注意的是,如果代码输出目标版本大于ES5,属性描述符将是未定义的。

下面的代码通过装饰器鞋工厂定义了一个简单的装饰器。 示例代码如下:

// 装饰器工厂
function enumerable(bool: boolean) {
  /**
   * 方法装饰器接受三个参数:
   * 1. target:对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
   * 2. propertyName:成员的名字
   * 3. descriptor:属性描述符,其类型为 PropertyDescriptor
   */
  return function (
    target: any,
    propertyName: string,
    descriptor: PropertyDescriptor,
  ) {
    // 根据传入的bool决定该方法是否枚举
    descriptor.enumerable = bool
  }
}
class Info {
  constructor(public name: string) {}
  @enumerable(false)
  getName() {
    return this.name
  }
}
const info = new Info('一碗周')
// 如果直接打印,该对象中不包含 getName() 方法,因为该方法是不可枚举的。
console.log(info) // { name: '一碗周' }
// 但是可以调用该方法
console.log(info.getName()) // 一碗周

在前面的代码中,我们直接通过装饰器对类中方法的属性描述符进行更改

如果方法装饰器返回一个值,则该值将用作该方法的属性描述符对象。 示例代码如下:

// 装饰器工厂
function enumerable(bool: boolean) {
  return function (
    target: any,
    propertyName: string,
    descriptor: PropertyDescriptor,
  ) {
    return {
      value: function () {
        return 'Error: name is undefined'
      },
      enumerable: bool,
    }
  }
}
class Info {
  constructor(public name: string) {}
  @enumerable(false)
  getName() {
    return this.name
  }
}
const info = new Info('一碗周')
console.log(info) // { name: '一碗周' }
console.log(info.getName()) // Error: name is undefined

里面的代码中,我们的方法装饰器返回了一个对象,而该对象的value属性改变了技能的定义,所以最终的结果是Error: name is undefined。

4.辅助装饰器

访问器装饰器就是我们之前学过的set和get方法。 一种是设置属性值触发,另一种是获取属性值时触发。

accessor装饰器也接受三个参数,与skill装饰器相同,这里不再赘述。

示例代码如下:

function enumerable(bool: boolean) {
  return function (
    target: any,
    propertyName: string,
    descriptor: PropertyDescriptor,
  ) {
    descriptor.enumerable = bool
  }
}
class Info {
  private _name: string
  constructor(name: string) {
    this._name = name
  }
  @enumerable(false)
  get name() {
    return this._name
  }
  set name(name) {
    this._name = name
  }
}

值得注意的是,TypeScript 不允许同时修饰成员的 get 和 set 访问器。

5. 属性装饰器

属性装饰器在属性声明之前声明。 它有两个参数,如下图

示例代码如下:

function printPropertyName(target: any, propertyName: string) {
  console.log(propertyName)
}
class Info {
  @printPropertyName
  name: string
  @printPropertyName
  age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}
new Info('一碗周', 18)

执行结果如下:

姓名

年龄

6.参数装饰器

参数装饰器有3个参数,如下:

参数装饰器的作用是监听一个方法的参数是否传入,参数装饰器的返回值会被忽略

示例代码如下:

function required(target: any, propertyName: string, index: number) {
  console.log(`修饰的是${propertyName}的第${index + 1}个参数`)
}
class Info {
  name: string = '一碗周'
  age: number = 18
  getInfo(prefix: string, @required infoType: string): any {
    return prefix + ' ' + this[infoType]
  }
}
interface Info {
  [key: string]: string | number | Function
}
const info = new Info()
info.getInfo('', 'age') // 修饰的是getInfo的第2个参数

这里我们在getInfo方法的第二个参数之前使用参数装饰器,这样我们就可以在装饰器中获取一些信息。

关于 TypeScript 装饰器定义的文章到此结束。 关于TypeScript装饰器的更多信息,请搜索Script House之前的文章或者继续浏览下面的相关文章。 希望大家以后多多支持Script House!

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 typescript typescript 装饰器实践-TypeScript 装饰器定义 https://www.wkzy.net/game/201530.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务