TypeScript學習: 十二、TS中的裝飾器


前言

裝飾器: 裝飾器是一種特殊類型聲明, 它能夠被附加到類聲明,方法,屬性或者參數上, 可以修改類的行為
通俗的講裝飾器就是一個方法, 可以注入到類,方法,屬性參數上來擴展類,屬性,方法,參數功能
常見的裝飾器:屬性裝飾器,方法裝飾器,參數裝飾器
寫法: 普通修飾器(無法傳參)、裝飾器工廠(可以傳參)
 

類修飾器

裝飾器在類聲明之前被執行,類裝飾器應用於類構造函數,可以用來監視,修改或者代替類定義
 

類普通裝飾器:

function logClass(params: any) { 
    console.log(params); 
}


@logClass
class HttpClient{
    constructor() {

    }
    getData() {

    }
 }

 定義了一個 logClass 類   並且帶了一個默認參數  params

這個 params == HttpClinent   

function logClass(params: any) {
    console.log(params); 
    params.prototype.httpUrl = "http.xxxxx"; // 通過原型鏈添加一個 給類添加一個屬性
}


@logClass
class HttpClient{
    constructor() {

    }
    getData() {

    }
 }

var httpClient = new HttpClient();
console.log(httpClient.httpUrl);

運行結果:

 

 通過 類裝飾器添加 方法

function logClass(params: any) {
    console.log(params); 
    params.prototype.httpUrl = "http.xxxxx"; // 通過原型鏈添加一個 給類添加一個屬性

    params.prototype.run = function() {
        console.log("run-app");
    }
}

@logClass
class HttpClient{
    constructor() { }
    getData() { }
 }

var httpClient = new HttpClient();
console.log(httpClient.httpUrl);
httpClient.run(); // 執行通過裝飾器添加的方法

 

 類裝飾器工廠:

function logClass(params: string) {
    console.log(params); // 傳入的參數類型
   return function(tarage:any) { 
        // tarage == HttpClient
   }
}

@logClass("傳入參數")
class HttpClient{
    constructor() { }
    getData() { }
}

var httpClient = new HttpClient();

 

 如果是裝飾器工廠必須要寫入 參數     @logClass("傳入參數")    

可以根據裝飾器傳入的參數去實現需要的功能

function logClass(params: string) {
    console.log(params); // 傳入的參數類型
   return function(tarage:any) { 
        // tarage == HttpClient
        tarage.prototype.apiUrl = params; // 通過原型鏈修改 類的屬性
   }
}

@logClass("http://xxxxxx123")
class HttpClient{
    constructor() { }
    getData() { }
}

var httpClient = new HttpClient();

 

而且還可以重載 構造函數
function logClass(target: any) {
    console.log(target);
   return class extends target{
        apiUrl:any="修改后的數據";
        getData() {
            this.apiUrl = this.apiUrl + "---===--";
            console.log(this.apiUrl);
        }
   }
}

@logClass
class HttpClient{
    public apiUrl: string | undefined;
    constructor() { 
        this.apiUrl = "我是構造函數里面的apiUrl";
    }
    getData() { 
        console.log(this.apiUrl);
    }
}

var httpClient = new HttpClient();
console.log(httpClient.apiUrl)
httpClient.getData();

 屬性裝飾器

 屬性裝飾器表達式會在運行時當作函數調用, 傳入2個參數
 * 第一個參數:對於靜態成員來說 是類的構造函數, 對於實例化成員是類的原型對象
 * 第二個參數:成員名字
function logProperty(params: any) {
    console.log("接收傳入的參數", params);
    return function(tarage: any, attr: any) {
        console.log("參數一:", tarage); // 對於實例化成員是類的原型對象
        console.log("參數二:", attr);// 成員名字
    }
}

class HttpClient{
    
    @logProperty("test")
    public url:string|undefined; // 這個屬性使用 屬性裝飾器
    
    constructor() {   }
    getData() {  }
}

 通過參數一   修改屬性值:

function logProperty(params: any) {
    console.log("接收傳入的參數", params);
    return function(tarage: any, attr: any) {
        console.log("參數一:", tarage); // 對於實例化成員是類的原型對象
        console.log("參數二:", attr);// 成員名字
        tarage[attr] = params; // 這里修改屬性值
    }
}

class HttpClient{
    
    @logProperty("test")
    public url:string|undefined; // 這個屬性使用 屬性裝飾器
    
    constructor() {   }
    getData() { 
        console.log( "url屬性值", this.url);
     }
}

var httpClient = new HttpClient();
httpClient.getData(); // 輸出     url屬性值 test

方法裝飾器

它會被應用到方法的 屬性描述符上, 可以用來監視,修改或者替換方法定義
 
 * 方法裝飾器會在運行時傳入3個參數
 *  參數一: 對於靜態成員來說是類的構造函數,對於實例成員是類的原型
 *  參數二: 成員名字
 *  參數三: 成員的屬性描述符。
function logMethod(params:any) {
    console.log("調用傳入的參數", params)
    return function(tarage:any, methodName: string, desc:any){
        console.log("參數一", tarage); // 實例成員是類的原型
        console.log("參數二", methodName); // 成員名字, 方法名
        console.log("參數三", desc); // 描述
    }
}



class HttpClient{
    
    public url:string|undefined;
    
    constructor() {   }

    @logMethod("get")
    getData() { // 這個方法使用了 裝飾器
        console.log( "url屬性值", this.url);
     }
}

 第一個參數是 實例成員的原型, 可以通過它給原型添加屬性或方法

function logMethod(params:any) {
    console.log("調用傳入的參數", params)
    return function(tarage:any, methodName: string, desc:any){
        console.log("參數一", tarage); // 實例成員是類的原型
        console.log("參數二", methodName); // 成員名字, 方法名
        console.log("參數三", desc); // 描述

        tarage.api = "我是裝飾器添加的 屬性";
        tarage.run = function() {
            console.log("我是裝飾器添加的方法");
        }
    }
}



class HttpClient{
    
    public url:string|undefined;
    
    constructor() {   }

    @logMethod("get")
    getData() { // 這個方法使用了 裝飾器
        console.log( "url屬性值", this.url);
     }
}

var httpClient = new HttpClient();
console.log(httpClient.api); // 輸出: 我是裝飾器添加的 屬性
httpClient.run();  // 輸出 我是裝飾器添加的方法

 

第三個參數是 描述 
修改裝飾器方法, 把裝飾器方法里面的所有參數修改為string類型
function logMethod(params:any) {
    console.log("調用傳入的參數", params)
    return function(tarage:any, methodName: string, desc:any){
       
       console.log(desc.value); // 輸出 function() { console.log( "url屬性值", this.url);}
       var methodFun = desc.value;
       desc.value = function(...args:any) { // 重寫 getData 方法
            args = args.map((value:any)=>{
                return String(value);
            });
            console.log(args);

            // 使用對象冒充, 還原之前的函數
            methodFun.apply(this, args); // 執行輸出 我是getData方法
       }
    }
}

class HttpClient{
    
    public url:string|undefined;
    
    constructor() {   }

    @logMethod("get")
    getData(...args:any) { // 這個方法使用了 裝飾器
        console.log(args);// 輸出: Array(2) ["123", "adb"]
        console.log( "我是getData方法");
     }
}

var httpclient = new HttpClient();
httpclient.getData(123, "adb");  // 輸出: Array(2) ["123", "adb"]

 

方法參數裝飾器

參數裝飾器表達式會在運行時當作函數調用,可以使用參數裝飾器為類的原型
增加一些元素數據,傳入三個參數:

參數一: 對於靜態成員來說是類的構造函數, 對於實例成員是類的原型對象
參數二:方法名稱
參數三:參數在函數參數列表中的索引
function logParams(params:any) {
    return function(target:any,methodName:any,paramsIndex:number){
        console.log(params);// 我是裝飾器參數
        console.log(target); // Object {getData: , constructor: }
        console.log(methodName); // getData
        console.log(paramsIndex);// 0
    }
}

class HttpClient{
    public url:string|undefined;
    constructor() {   }

    getData(@logParams("我是裝飾器參數")uuid:any) { // 這個方法使用了 裝飾器
        console.log(uuid);
        console.log( "我是getData方法");
     }
}

var httpClinet = new HttpClient();
httpClinet.getData("test");

 

 注意裝飾器的執行順序:

屬性裝飾器>方法裝飾器>方法參數裝飾器>類裝飾器

如果一個方法有兩個裝飾器, 那么 后面的裝飾器先執行,再到前面的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM