typescript-裝飾器(七)

裝飾器

  1. 裝飾器是一種特殊的類型聲明,它可以被附加到類聲明、方法、屬性、參數上,能夠修改類的行爲;
  2. 通俗來說裝飾器就是一個方法,能夠 被注入到類、方法、屬性、參數上來擴展類、方法、屬性、參數的功能;
  3. 常見裝飾器有:類裝飾器、方法裝飾器、屬性裝飾器、參數裝飾器;
  4. 裝飾器寫法:普通裝飾器(沒法傳參)、裝飾器工廠(可傳參)
  5. 裝飾器是過去幾年最大成就之一,已經是es7標準特性之一;

類裝飾器

  • 類裝飾器在類聲明以前被聲明,(緊靠着類聲明),類裝飾器應用於類構造函數,能夠用來監視、修改或替換類定義;
// 類裝飾器:普通裝飾器(沒法傳參)
function logClass(params){
    // params 就是當前類
    console.log(params)
    params.prototype.apiUrl = "動態擴展的屬性"
    params.prototype.fetch = function(){
        console.log('我是一個fetch方法')
    }
}

@logClass
class HttpClient {
    constructor(){

    }

    getData(){

    }
}

let http = new HttpClient()
console.log(http.apiUrl) // 動態擴展的屬性

http.fetch() // 我是一個fetch方法
// 類裝飾器:裝飾器工廠(能夠傳參)
function logClass(params){
    console.log(params)
    // params調用時的實參
    return function(target){
        // target 當前類 HttpClient
          console.log(target)
        params.prototype.apiUrl = params
    }
}

@logClass('newbanker')
class HttpClient {
    constructor(){

    }

    getData(){

    }
}

let http = new HttpClient()
console.log(http.apiUrl) // newbanker
// 裝飾器能夠修改當前類的構造函數和方法
// 類裝飾器表達式會在運行時當作函數被調用,類的構造函數做爲其惟一參數
// 若是類裝飾器返回一個值,它會使用提供的構造函數來替換類的聲明
// 下面是一個函數重載的例子
function logClass(params){
    console.log(params)
    // params調用時的實參
    return class extends target {

        apiUrl = "我是修改後的數據"
        getData(){
            console.log(this.apiUrl+'------')
        }
    }
}

@logClass
class HttpClient {
    constructor(){
        this.apiUrl = "我是構造函數裏面的apiUrl"
    }

裝飾器

  1. 裝飾器是一種特殊的類型聲明,它可以被附加到類聲明、方法、屬性、參數上,能夠修改類的行爲;
  2. 通俗來說裝飾器就是一個方法,能夠 被注入到類、方法、屬性、參數上來擴展類、方法、屬性、參數的功能;
  3. 常見裝飾器有:類裝飾器、方法裝飾器、屬性裝飾器、參數裝飾器;
  4. 裝飾器寫法:普通裝飾器(沒法傳參)、裝飾器工廠(可傳參)
  5. 裝飾器是過去幾年最大成就之一,已經是es7標準特性之一;

類裝飾器

  • 類裝飾器在類聲明以前被聲明,(緊靠着類聲明),類裝飾器應用於類構造函數,能夠用來監視、修改或替換類定義;
// 類裝飾器:普通裝飾器(沒法傳參)
function logClass(params){
    // params 就是當前類
    console.log(params)
    params.prototype.apiUrl = "動態擴展的屬性"
    params.prototype.fetch = function(){
        console.log('我是一個fetch方法')
    }
}

@logClass
class HttpClient {
    constructor(){

    }

    getData(){

    }
}

let http = new HttpClient()
console.log(http.apiUrl) // 動態擴展的屬性

http.fetch() // 我是一個fetch方法
// 類裝飾器:裝飾器工廠(能夠傳參)
function logClass(params){
    console.log(params)
    // params調用時的實參
    return function(target){
        // target 當前類 HttpClient
          console.log(target)
        params.prototype.apiUrl = params
    }
}

@logClass('newbanker')
class HttpClient {
    constructor(){

    }

    getData(){

    }
}

let http = new HttpClient()
console.log(http.apiUrl) // newbanker
// 裝飾器能夠修改當前類的構造函數和方法
// 類裝飾器表達式會在運行時當作函數被調用,類的構造函數做爲其惟一參數
// 若是類裝飾器返回一個值,它會使用提供的構造函數來替換類的聲明
// 下面是一個函數重載的例子
function logClass(params){
    console.log(params)
    // params調用時的實參
    return class extends target {

        apiUrl = "我是修改後的數據"
        getData(){
            console.log(this.apiUrl+'------')
        }
    }
}

@logClass
class HttpClient {
    constructor(){
        this.apiUrl = "我是構造函數裏面的apiUrl"
    }

    getData(){
        console.log(this.apiUrl)
    }
}

let http = new HttpClient()
console.log(http.apiUrl) // 我是修改後的數據

屬性裝飾器

  • 屬性裝飾器會在運行時當作函數被調用,傳入下列兩個參數:
    • 對應靜態成員來講是類的構造函數,對於實例成員是類的原型對象;
    • 屬性成員的名稱;
// 類裝飾器:裝飾器工廠(能夠傳參)
function logClass(params){
    console.log(params)
    // params調用時的實參
    return function(target){
        // target 當前類 HttpClient
          console.log(target)
    }
}

// 屬性裝飾器
function logProperty(params){
    return function(target, attr){
        console.log(target) //
        console.log(attr) // 當前屬性url
        target.attr = params
    }
}

@logClass
class HttpClient {
  @logProperty('https://baidu.com')
    public url

    getData(){

    }
}

方法裝飾器

  • 方法裝飾器會被用到方法的屬性描述符上,能夠用來監視、修改或者替換方法定義;
  • 方法裝飾器會在運行時傳入如下3個參數:
    • 對於靜態成員來講是類的構造函數,對於實例來講是類的原型對象;
    • 成員的名字
    • 成員的屬性描述符
// 方法裝飾器
function logMethod(params){
    return function(target, methodName, desc){
        console.log(target) // 原型對象,能夠擴展類的原型屬性和方法;
        // 能夠擴展當前實例的屬性和方法
        target.apiUrl = "http://www.sina.cn"
        target.run = function(){
            console.log('run')
        }

        console.log(methodName) // 當前方法名 getData
        // 修改裝飾器的方法,把裝飾器方法裏面傳入的全部參數改成string類型;
        //  保存當前方法
        let save = desc.value
        desc.value = function(...args){
            args.map((v) => {
                return String(v)
            })
            console.log(v)
        }

        console.log(desc) // 描述信息  { value: f, xxx: xxx }
        // 不加此方法會直接替換實例的方法,加上會修改
        save.apply(this, args) // 把當前方法this傳進去,表明在這個方法裏面調用save方法;並傳入參數;
    }
}

class HttpClient {
    public url: any | undefind;
    constructor(){

    }

    @get('http://www.baidu.com')
    getData(args){
        console.log(args) // ['123', 'string']
        console.log('我是getData的method')
    }
}

let http = new HttpClient();

console.log(http.apiUrl) // http://www.sina.cn
http.getData(123, 'string')

方法參數裝飾器

  • 參數裝飾器表達式會在運行時當作函數被調用,能夠使用參數裝飾器爲類的原型增長一些元素數據,傳入下列三個參數;
    • 對應靜態成員來講是類的構造函數,對應實例成員是類的原型對象
    • 參數的名字
    • 參數在函數參數列表中的索引
// 方法參數裝飾器
function logParams(params){
    return function(target, paramsName, paramsIndex){
        console.log(params) // xxxx
        console.log(target) //
        console.log(paramsName) // getData
        console.log(paramsIndex) // 0
    }
}

class HttpClient {
    getData(@logParams1('xxxx') uuid: any, @logParams2('xxxx') name: any){
        console.log(uuid) // 123
    }
}
let http: any = new HttpClient();

http.getData(123)

裝飾器執行順序

  • 屬性 》 方法 》 方法參數 》 類
  • 統一類型的裝飾器,若是有多個,從後往前、從下往上執行
@logClass1('http:www.baidu.con')
@logClass2('xxxx')
class HttpClient {
    @logAttribute()
    public apiUrl: string | undefind

    constructor(){

    }

    @logMethod()
    getData(){

    }

    setData(@logParams1() attr1: any, @logParams2() attr2: any){

    }
}

let http: any = new HttpClient();
// 屬性裝飾器 > 方法裝飾器 > 方法參數裝飾器2 > 方法參數裝飾器1 > 類裝飾器2 > 類裝飾器1
相關文章
相關標籤/搜索