欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

TypeScript 裝飾器定義

 更新時(shí)間:2021年12月10日 09:42:26   作者:一碗周  
這篇文章主要介紹了TypeScript 裝飾器定義,裝飾器是一種新的聲明,它可以作用于類聲明 、方法 、訪問(wèn)器 、屬性以及參數(shù)上,下面我們就來(lái)看看TypeScript 裝飾器的具體定義吧,需要的朋友可以參考一下,希望對(duì)你有所幫助

前言:

裝飾器Decorator ECMAScript中已經(jīng)提案,但是目前還沒(méi)有定案;在TypeScript中已經(jīng)將其實(shí)現(xiàn),但是這仍是一項(xiàng)正在試驗(yàn)中的特性,如果想要使用裝飾器,需要在tsconfig.json中將experimentalDecorators屬性,將其設(shè)置為true。

1.概念

1.1定義

裝飾器是一種新的聲明,它可以作用于類聲明 、方法 、訪問(wèn)器 、屬性 以及參數(shù) 上。裝飾器的使用采用@符號(hào)加一個(gè)函數(shù)名稱,例如@testDecorator,其中,這個(gè)testDecorator必須是一個(gè)函數(shù)或者 return一個(gè)函數(shù) ,這個(gè)函數(shù)在運(yùn)行的時(shí)候被調(diào)用,被裝飾的聲明作為參數(shù)會(huì)自動(dòng)傳入。

值得注意的是 ,裝飾器要緊挨著要修飾的內(nèi)容的前面 ,而且所有的裝飾器不能用在聲明文件.d.ts.中,和任何外部上下文中(比如declare)。

裝飾器的定義以及使用如下所示:

// 定義一個(gè)函數(shù)作為裝飾器函數(shù)使用
function testDecorator() {}

// 通過(guò)@符號(hào)使用裝飾器
@testDecorator

1.2裝飾器工廠

所謂的裝飾器工廠也是一個(gè)函數(shù),與普通的裝飾器函數(shù)不同的是它的返回值是一個(gè)函數(shù),返回的函數(shù)作為裝飾器調(diào)用的函數(shù)。如果使用裝飾器工廠,可以在使用的時(shí)候根據(jù)當(dāng)前的使用情況,傳遞不同的參數(shù),但是在使用的時(shí)候,就需要加上函數(shù)調(diào)用。

示例代碼如下:

// 裝飾器工廠,返回值是一個(gè)函數(shù)
function testDecorator() {
    return function() {}
}

// 通過(guò)@符號(hào) + 函數(shù)調(diào)用的方式使用裝飾器
@testDecorator()

1.3裝飾器組合使用

裝飾器是可以組合使用的,也就是說(shuō)可以對(duì)用一個(gè)目標(biāo),引用多個(gè)裝飾器,

示例代碼如下所示:

// 定義兩個(gè)裝飾器函數(shù)
function setName() {}
function setAge() {}

// 使用裝飾器
@setName
@setAge
class Person {}

如果使用多個(gè)裝飾器,裝飾器的執(zhí)行是有順序的,執(zhí)行順序如下:

如果使用的普通的裝飾器函數(shù)的話,執(zhí)行順序是從下往上執(zhí)行的,

示例代碼如下:

function setName(constructor: any) {
  console.log('setName', constructor)
}
function setAge(constructor: any) {
  console.log('setAge', constructor)
}
@setName
@setAge
class Person {}
/* 執(zhí)行結(jié)果如下:
setAge [Function: Person]
setName [Function: Person]
*/


如果是裝飾器工廠的,它的執(zhí)行順序是先從上到下依次執(zhí)行工廠函數(shù),然后從下往上依次執(zhí)行工廠函數(shù)return的函數(shù)。示例代碼如下

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 {}
/* 執(zhí)行結(jié)果如下:
get setName
get setAge
setAge [Function: Person]
setName [Function: Person]
*/

1.4裝飾器求值

類的定義中不同聲明上的裝飾器將按以下規(guī)定的順序引用:

  • 參數(shù)裝飾器,方法裝飾器,訪問(wèn)符裝飾器或?qū)傩匝b飾器應(yīng)用到每個(gè)實(shí)例成員;
  • 參數(shù)裝飾器,方法裝飾器,訪問(wèn)符裝飾器或?qū)傩匝b飾器應(yīng)用到每個(gè)靜態(tài)成員;
  • 參數(shù)裝飾器應(yīng)用到構(gòu)造函數(shù);
  • 類裝飾器應(yīng)用到類。

2.類裝飾器

類裝飾器 在類聲明之前使用,必須緊挨著需要裝飾的內(nèi)容,類裝飾器應(yīng)用于類的聲明。

類裝飾器表達(dá)式會(huì)在運(yùn)行時(shí)當(dāng)做函數(shù)被調(diào)用,它有一個(gè)參數(shù),就是這個(gè)類的構(gòu)造函數(shù)。

示例代碼如下:

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的原型對(duì)象的constructor屬性指向的其實(shí)就是Info本身。

我們還可以通過(guò)裝飾器來(lái)修改類的原型對(duì)象和構(gòu)造函數(shù),示例代碼如下:

// * 通過(guò)裝飾器 修改原型對(duì)象與構(gòu)造函數(shù)
function addName(constructor: { new (): any }) {
  constructor.prototype.name = '一碗周'
}
@addName
class Person {}
const person = new Person()
console.log(person.name) // error 類型“A”上不存在屬性“name”

在上面的代碼中,我們通過(guò)addName修飾符在類Person的原型上添加一個(gè)name屬性,這樣使得通過(guò)Person類實(shí)例化的對(duì)象,都可以訪問(wèn)name這個(gè)屬性,但是實(shí)際上并不是這樣的,這里已經(jīng)拋出一個(gè)異常,想要解決這個(gè)問(wèn)題,可以通過(guò)類型斷言的方式,也可以通過(guò)定義一個(gè)同名接口,通過(guò)聲明合并的方式解決這個(gè)問(wèn)題。

示例代碼如下:

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) // 一碗周

而且我們還可以通過(guò)裝飾器重載構(gòu)造函數(shù),示例代碼如下:

// * 重載構(gòu)造函數(shù)
function classDecorator<T extends { new (...args: any[]): {} }>(
  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)
/* 執(zhí)行結(jié)果如下:
{
  age: 18,
  name: '一碗周',
  hobby: 'coding',
}
*/

我們還可以通過(guò)裝飾器工廠的方式來(lái)傳遞參數(shù),示例代碼如下:

// 定義一個(gè)裝飾器工廠
function classDecorator(_name: string) {
  return function <T extends { new (...args: any[]): {} }>(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)
/* 執(zhí)行結(jié)果如下:
{
  age: 18,
  name: '一碗周',
  hobby: 'coding',
}
*/

3.方法裝飾器

方法裝飾器用來(lái)處理類中的方法,它可以處理方法的屬性描述符(關(guān)于什么是屬性描述符,請(qǐng)參考Object.defineProperty() ),也可以處理方法定義。方法裝飾器在運(yùn)行時(shí)也是被當(dāng)做函數(shù)調(diào)用,其包含三個(gè)參數(shù),

具體如下所示:

對(duì)于靜態(tài)成員來(lái)說(shuō)是類的構(gòu)造函數(shù),對(duì)于實(shí)例成員是類的原型對(duì)象。

成員的名字。

成員的屬性描述符 。

值得注意的是如果代碼輸出目標(biāo)版本小于ES5,屬性描述符 將會(huì)是undefined

如下代碼通過(guò)裝飾器工廠定義了一個(gè)簡(jiǎn)單的方法裝飾器,示例代碼如下:

// 裝飾器工廠
function enumerable(bool: boolean) {
  /**
   * 方法裝飾器接受三個(gè)參數(shù):
   * 1. target:對(duì)于靜態(tài)成員來(lái)說(shuō)是類的構(gòu)造函數(shù),對(duì)于實(shí)例成員是類的原型對(duì)象
   * 2. propertyName:成員的名字
   * 3. descriptor:屬性描述符,其類型為 PropertyDescriptor
   */
  return function (
    target: any,
    propertyName: string,
    descriptor: PropertyDescriptor,
  ) {
    // 根據(jù)傳入的bool決定該方法是否可枚舉
    descriptor.enumerable = bool
  }
}
class Info {
  constructor(public name: string) {}
  @enumerable(false)
  getName() {
    return this.name
  }
}
const info = new Info('一碗周')
// 如果直接打印,該對(duì)象中不包含 getName() 方法,因?yàn)樵摲椒ㄊ遣豢擅杜e的。
console.log(info) // { name: '一碗周' }
// 但是可以調(diào)用該方法
console.log(info.getName()) // 一碗周

在上面的代碼中,我們直接通過(guò)裝飾器對(duì)類中的方法的屬性描述符進(jìn)行了修改。

如果方法裝飾器返回一個(gè)值,那么會(huì)用這個(gè)值作為方法的屬性描述符對(duì)象,示例代碼如下:

// 裝飾器工廠
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

在上面的代碼中,我們的方法裝飾器中返回了一個(gè)對(duì)象,該對(duì)象的value屬性修改了方法的定義,所以最終看到的結(jié)果為Error: name is undefined。

4.訪問(wèn)器裝飾器

訪問(wèn)器裝飾器就是之前所學(xué)習(xí)的setget方法,一個(gè)在設(shè)置屬性值的時(shí)候觸發(fā),一個(gè)在獲取屬性值的時(shí)候觸發(fā)。

訪問(wèn)器裝飾器同樣也接受三個(gè)參數(shù),與方法裝飾器一樣,這里不做贅述了,

示例代碼如下:

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不允許同時(shí)裝飾一個(gè)成員的getset訪問(wèn)器。

5.屬性裝飾器

屬性裝飾器聲明在屬性聲明之前,它有兩個(gè)參數(shù),如下所示:

  • 對(duì)于靜態(tài)成員來(lái)說(shuō)是類的構(gòu)造函數(shù),對(duì)于實(shí)例成員是類的原型對(duì)象。
  • 成員的名字。

示例代碼如下:

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)

執(zhí)行結(jié)果如下:

name
age

6.參數(shù)裝飾器

參數(shù)裝飾器具有三個(gè)參數(shù),具體如下:

  • 對(duì)于靜態(tài)成員來(lái)說(shuō)是類的構(gòu)造函數(shù),對(duì)于實(shí)例成員是類的原型對(duì)象。
  • 成員的名字。
  • 參數(shù)在函數(shù)參數(shù)列表中的索引。

參數(shù)裝飾器的作用是用于監(jiān)視一個(gè)方法的參數(shù)是否被傳入,參數(shù)裝飾器的返回值會(huì)被忽略。

示例代碼如下:

function required(target: any, propertyName: string, index: number) {
  console.log(`修飾的是${propertyName}的第${index + 1}個(gè)參數(shù)`)
}
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個(gè)參數(shù)


這里我們?cè)?code>getInfo方法的第二個(gè)參數(shù)之前使用參數(shù)裝飾器,從而可以在裝飾器中獲取到一些信息。

到此這篇關(guān)于TypeScript 裝飾器定義的文章就介紹到這了,更多相關(guān)TypeScript 裝飾器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論