<center id="qkqgy"><optgroup id="qkqgy"></optgroup></center>
  • <menu id="qkqgy"></menu>
    <nav id="qkqgy"></nav>
    <xmp id="qkqgy"><nav id="qkqgy"></nav>
  • <xmp id="qkqgy"><menu id="qkqgy"></menu>
    <menu id="qkqgy"><menu id="qkqgy"></menu></menu>
    <tt id="qkqgy"><tt id="qkqgy"></tt></tt>

  • <>一、裝飾器運行環境

    裝飾器是一項實驗性特性,在未來的版本中可能會發生改變。

    若要啟用實驗性的裝飾器特性,你必須在命令行或tsconfig.json里啟用experimentalDecorators編譯器選項:

    * tsconfig.json: { "compilerOptions": { "target": "ES5",
    "experimentalDecorators": true } }
    <>二、什么是裝飾器

    TypeScript中的裝飾器是一種可以附加到類、方法、屬性或參數
    上的特殊聲明。裝飾器提供了一種在編譯時檢測類型和運行時修改行為的機制,在許多框架中得到了廣泛的應用。

    它們本質上是函數,可以接收一個或多個參數,并返回新的目標對象。

    裝飾器是為元素(類、方法、屬性、參數)添加注解的語法糖,提供了一種簡潔優雅的方式來描述元素的特性。當我們在使用裝飾器時,它實際上是在目標元素周圍創建一個包裝器函數,以便在目標元素被調用或使用時運行一些代碼。

    在編譯時,TypeScript編譯器將自動將裝飾器轉換為底層JavaScript代碼。在編譯后的JavaScript代碼中,裝飾器被轉換為一系列函數調用,這些函數執行了被裝飾元素的包裝器函數,并返回了新的包裝器函數。

    通過使用裝飾器,我們可以在不修改被裝飾元素代碼的情況下,動態地添加或修改其行為。這使得我們可以在運行時或編譯時優化代碼、實現依賴注入、添加日志或驗證等功能。

    <>三、裝飾器擴展類的屬性

    裝飾器可以用來擴展類的屬性,例如添加額外的元數據信息或者添加一些行為。下面我們以添加元數據信息為例進行說明:
    function logClass(target: any) { // 保存類構造函數原型對象引用 const original = target.
    prototype; // 重新定義構造函數 const constructor = function (...args) { console.log(`
    Creating instance with arguments:${args}`); // 調用原來的構造函數 original.constructor.
    apply(this, args); }; // 給構造函數添加元數據 Object.defineProperty(constructor, 'name', {
    value: target.name }); Object.defineProperty(constructor, 'description', {
    value: 'This is a decorated class' }); // 重新定義構造函數原型對象 constructor.prototype =
    original; // 返回新的構造函數 return constructor; } @logClass class MyClass {
    constructor(public x: number, public y: number) {} } const myObj = new MyClass(1
    , 2); console.log(myObj.constructor.name); // 輸出"MyClass" console.log(myObj.
    constructor.description); // 輸出"This is a decorated class"
    在上面的代碼中,我們定義了一個logClass
    裝飾器函數,它接受一個類的構造函數作為參數,并返回一個新的類構造函數。在這個裝飾器函數里,我們保存了原來的類構造函數原型對象引用,并重新定義了新的構造函數。在重新定義構造函數的時候,我們給它添加了一些元數據信息,在這個例子中是類的名字和一個描述信息。最后我們再把原來的構造函數原型對象重新賦值給新的構造函數原型對象,并返回這個新的構造函數。

    我們使用@logClass裝飾器修飾MyClass類,這樣就會在類定義的時候調用logClass函數,并將MyClass類的構造函數作為參數傳遞進去。
    logClass函數會把類的構造函數進行處理,并在元數據信息中添加上我們定義的內容。

    當我們創建了一個MyClass的實例對象后,我們可以通過訪問它的構造函數的name和description
    屬性來獲取到我們剛才添加的元數據信息。這個例子中我們添加的只是一些簡單的元數據信息,但是在實際開發中,我們可以利用裝飾器添加更加復雜的元數據信息和行為。

    <>四、裝飾器工廠

    裝飾器工廠是TypeScript中一種用于創建裝飾器的方法,它返回一個具體的裝飾器函數,在裝飾器修飾的類、屬性、方法或參數上添加附加的元數據或行為。

    裝飾器工廠的本質是一個函數,它可以接收參數,并返回一個裝飾器函數。裝飾器函數可以用來修改或增強原有的類、屬性、方法或參數,實現各種創造性的功能。

    在實際開發中,裝飾器工廠可以用于很多場景,如:

    * 實現日志、權限、緩存等功能的統一處理;
    * 用于依賴注入,在編譯時自動注入依賴對象,避免手動管理依賴關系;
    * 實現類似于Spring AOP的橫向切面編程,實現方法執行前、執行后、異常處理等等;
    下面舉例說明一個簡單的裝飾器工廠:
    function log(className: string) { return function(target: any, propertyKey:
    string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.
    value; descriptor.value = function (...args: any[]) { console.log(`[${className}
    ]${propertyKey} is called with arguments ${args.join(', ')}`); const result =
    originalMethod.apply(this, args); console.log(`[${className}] ${propertyKey}
    returned${result}`); return result; } return descriptor; } }
    這個裝飾器工廠定義了一個log方法,它返回一個裝飾器函數。裝飾器函數用于打印方法調用的日志。

    我們可以在類的方法上使用這個裝飾器工廠,如:
    class Calculator { @log('Calculator') add(a: number, b: number) { return a + b;
    } }
    此時,當我們調用Calculator類的add方法時,就會輸出日志,如:
    const calculator = new Calculator(); calculator.add(1, 2); // 輸出:[Calculator]
    add is called with arguments 1, 2 // 輸出:[Calculator] add returned 3
    這樣就實現了一個簡單的裝飾器工廠,利用它可以實現更加復雜和高級的功能。

    <>五、屬性裝飾器

    在TypeScript中,屬性裝飾器是裝飾類的屬性的一種方式。下面詳細介紹一下屬性裝飾器的使用及其參數含義。

    屬性裝飾器的使用

    屬性裝飾器是指裝飾一個類中的屬性,即為類的屬性添加一些元數據,通常用來定義屬性的屬性描述符或為屬性添加一些額外行為,例如實現屬性計算等。

    屬性裝飾器使用@符號和一個函數表示,類似于方法裝飾器。
    class MyClass{ @myDecor // <-- 這里是屬性裝飾器 myProp: string; } function myDecor(
    target: any, propertyKey: string) { // 這里可以對屬性進行修改或設置元數據 }
    屬性裝飾器的參數含義

    屬性裝飾器函數有兩個參數,分別是target和propertyKey
    。在裝飾實例屬性、靜態屬性、實例方法時,參數所代表的含義是有所不同的,下面我們分別舉例介紹。

    <>1. 裝飾實例屬性

    裝飾實例屬性時,target表示類的原型對象(即類的實例化對象的__proto__屬性),propertyKey表示被裝飾的屬性名。
    class MyClass { @myDecorator myProp: string; } function myDecorator(target: any
    , propertyKey: string) { console.log(target); // MyClass 的原型對象 console.log(
    target.constructor); // MyClass console.log(propertyKey); // 'myProp' }
    在實例化對象后,裝飾器會被應用于該實例中的屬性。
    const myInstance = new MyClass(); console.log(myInstance.myProp); // undefined
    <>2. 裝飾靜態屬性

    裝飾靜態屬性時,target表示的是類的構造函數本身,propertyKey表示被裝飾的屬性名。
    class MyClass { @myDecorator static myStaticProp: string; } function
    myDecorator(target: any, propertyKey: string) { console.log(target); // MyClass
    構造函數本身 console.log(target.constructor); // MyClass console.log(propertyKey); //
    'myStaticProp' }
    在訪問靜態屬性時,裝飾器會被應用于該類本身。
    console.log(MyClass.myStaticProp); // undefined
    <>3. 裝飾實例方法

    當屬性裝飾器裝飾實例時,裝飾器的參數包括三個:

    * target:被裝飾的類的實例(即構造函數的原型對象)。
    * propertyKey:被裝飾的屬性的名稱。
    * descriptor:被裝飾屬性的屬性描述符(Object.defineProperty中的描述符對象)。
    舉個例子,假設我們有一個User類,其中有一個屬性age表示用戶的年齡。我們可以使用屬性裝飾器保證age屬性的取值范圍在0到120之間,代碼如下:
    function rangeValidator(target: any, propertyKey: string, descriptor:
    PropertyDescriptor) { const originalSetter = descriptor.set; descriptor.set =
    function (value: number) { if (value < 0 || value > 120) { throw new Error(
    'Invalid age value!'); } originalSetter.call(this, value); }; } class User {
    private _age: number; @rangeValidator public get age(): number { return this.
    _age; } public set age(age: number) { this._age = age; } } const user = new User
    (); user.age = 25; // OK user.age = 200; // Error: Invalid age value!

    在這個例子中,rangeValidator是一個屬性裝飾器函數,它接收三個參數:target、propertyKey和descriptor。我們在裝飾器函數中重寫了age屬性的setter方法,并在新的setter方法中添加了取值范圍的驗證邏輯。當我們使用@rangeValidator裝飾age屬性時,TypeScript會自動把User類傳遞給rangeValidator函數的target參數,把age屬性的名稱"age"傳遞給propertyKey參數,把age屬性的屬性描述符傳遞給descriptor參數。通過這些參數,我們就可以得到被裝飾的類、屬性和屬性的描述對象,并對它們進行一些操作。

    <>六、參數裝飾器

    TypeScript中的參數裝飾器是一種特殊類型的裝飾器,它可以用于裝飾函數或方法中的參數。參數裝飾器可以提供對函數或方法中傳入參數的處理和校驗功能。

    在參數裝飾器中,通常會接收三個參數:target、methodName和paramIndex。

    * target:表示被裝飾的類的原型對象(靜態成員)或類的構造函數
    (非靜態成員)。如果裝飾的是靜態成員,則target是類的構造函數;如果裝飾的是非靜態成員,則target是類的原型對象。
    * methodName:表示被裝飾的方法的名稱。
    * paramIndex:表示被裝飾的參數在函數或方法的參數列表中的索引位置。
    下面分別舉例說明:

    <>1. 裝飾靜態成員時的應用

    在以下例子中,參數裝飾器用于校驗對象的id屬性是否為有效值,如果無效,則拋出異常。
    class Person { static instances = new Map<number, Person>(); constructor(public
    id: number) { Person.instances.set(id, this); } static getPersonById(@IsValidId
    id: number) { return Person.instances.get(id); } } function IsValidId(target:
    any, methodName: string, paramIndex: number) { let originalMethod = target[
    methodName]; target[methodName] = function (...args: any[]) { let id = args[
    paramIndex]; if (!Number.isInteger(id) || id <= 0 || id >= 1000) { throw new
    Error("Invalid id"); } return originalMethod.apply(this, args); } }
    <>2. 裝飾非靜態成員時的應用

    在以下例子中,參數裝飾器用于記錄函數執行時間。
    class Demo { log(@LogTime message: string) { console.log(message); } } function
    LogTime(target: any, methodName: string, paramIndex: number) { let
    originalMethod= target[methodName]; target[methodName] = function (...args: any[
    ]) { console.time(`${methodName}_${paramIndex}`); let result = originalMethod.
    apply(this, args); console.timeEnd(`${methodName}_${paramIndex}`); return result
    ; } } const demo = new Demo(); demo.log("start"); // 輸出:start, start_0: 0.653ms
    需要注意的是,參數裝飾器并不會修改方法簽名,因此需要在使用參數裝飾器時,保持方法簽名不變。

    <>七、裝飾器執行順序

    TypeScript中裝飾器的執行順序規律:

    * 對于一個類,先執行類中屬性的裝飾器,然后是方法的裝飾器,最后是類的裝飾器。即裝飾器的執行順序為:
    屬性裝飾器 -> 方法裝飾器 -> 類裝飾器

    其中,后寫的裝飾器會先執行,也就是先執行最后一個裝飾器,然后依次向前執行其他裝飾器。

    * 對于類中的方法和方法參數,裝飾器的執行順序為:
    方法參數裝飾器 -> 方法裝飾器

    即先執行方法參數的裝飾器,然后再執行方法的裝飾器。

    * 對于同一屬性或方法,如果有多個裝飾器,它們的執行順序由它們在代碼中的順序來決定。即先寫的裝飾器會先執行。
    舉例如下:
    function classDecorator1(target: any) { console.log("classDecorator1"); }
    function classDecorator2(target: any) { console.log("classDecorator2"); }
    function methodDecorator(target: any, propertyKey: string, descriptor:
    PropertyDescriptor) { console.log("methodDecorator"); } function paramDecorator(
    target: Object, propertyKey: string, parameterIndex: number) { console.log(
    "paramDecorator"); } @classDecorator1 @classDecorator2 class MyClass { @
    propertyDecorator myProperty: number; @methodDecorator myMethod(@paramDecorator
    param1: string, @paramDecorator param2: number) { console.log("MyClass.myMethod"
    ); } }
    對于上面的代碼,執行結果為:
    paramDecorator paramDecorator methodDecorator propertyDecorator
    classDecorator2 classDecorator1
    因為參數裝飾器是最先執行的,所以先輸出了參數裝飾器的內容;接著是方法裝飾器和屬性裝飾器;最后是類裝飾器
    ,按照后寫的裝飾器會先執行的原則,先執行classDecorator2再執行classDecorator1。

    總結:

    先上后下 先內后外

    * 屬性和方法:先上后下
    * 整體原則:先內后外

    技術
    下載桌面版
    GitHub
    百度網盤(提取碼:draw)
    Gitee
    云服務器優惠
    阿里云優惠券
    騰訊云優惠券
    華為云優惠券
    站點信息
    問題反饋
    郵箱:ixiaoyang8@qq.com
    QQ群:766591547
    關注微信
    巨胸美乳无码人妻视频