JS 中的裝飾器

js 中的裝飾器仍是一個提案,須要 babel 才能夠使用。它仍是一項實驗性特性,在將來的版本中可能會發生改變。javascript

裝飾器是一個函數,它只能做用於類不能做用於(由於函數提高),它以一個@符號開頭,以下:java

function d(target) { return target }

@d
class A {}

// 它至關於把類做爲參數傳遞給 d 函數,而後再返回一個被函數修改過的類
// 等同於
A = d(A) || A
複製代碼

它還能夠傳遞自定義參數和使用多個裝飾器node

function a(p) {
    console.log(1)
    return (target => {
        console.log(2)
        return target
    })
}
function b(target) {
    console.log(3)
    return target
}

@b
@a(1)
class A {}

// 打印順序是 1 2 3
複製代碼

多個裝飾器除了一行寫一個,也能夠全都寫在一行@b @a(1)react

在 react-redux 應用中使用裝飾器能夠這樣使用 connect 方法git

@connect(mapStateToProps, mapDispatchToProps)
export default class Comp extends Component {}
複製代碼

方法的裝飾

裝飾器除了做用於類,還能夠做用於類的方法。github

function d(target, name, desc) {
    // target 是類的原型對象
    // name 是函數的名字
    // desc 是屬性描述符
    let oldValue = desc.value;

    desc.value = function() {
        console.log(`Calling ${name} with`, arguments);
        return oldValue.apply(this, arguments);
    };

    return desc
    // 若是方法裝飾器返回一個值,它會被用做方法的屬性描述符。
}

class A {
    @d
    fn () {}
}
複製代碼

在 TypeScript 中方法裝飾器的 target 參數,對於靜態成員來講是類的構造函數,對於實例成員是類的原型對象。redux

屬性裝飾器

在 TypeScript 中裝飾器還能夠做用於屬性。babel

function d(target, name) {
    // target 對於靜態成員來講是類的構造函數,對於實例成員是類的原型對象。
    // name 屬性的名字
}

class A() {
    @d
    greeting: string;
}
複製代碼

參數裝飾器

TypeScript 中還能夠裝飾參數,app

function Query(target, name, index) {
    // target 對於靜態成員來講是類的構造函數,對於實例成員是類的原型對象
    // name 方法的函數名
    // index 參數的索引 從 0 開始
    // 參數裝飾器的返回值會被忽略。
}

class A() {
    fn(@Query query: Object) {
        
    }
}
複製代碼

存取裝飾器

TypeScript 中裝飾器也能夠裝飾存取聲明函數。框架

function d(target, name, desc) {
    // target 對於靜態成員來講是類的構造函數,對於實例成員是類的原型對象
    // name 函數名
    // desc 屬性描述符
    return desc
    // 若是方法裝飾器返回一個值,它會被用做屬性描述符
}

class A() {
    @d
    get a() {}
}
複製代碼

裝飾器求值

TypeScript 多個裝飾器執行順序是,

  1. 參數裝飾器,而後是方法裝飾器,訪問符裝飾器或屬性裝飾器應用到每一個實例成員
  2. 參數裝飾器,而後是方法裝飾器,訪問符裝飾器或屬性裝飾器應用到每一個靜態成員
  3. 參數裝飾器應用到構造函數
  4. 類裝飾器應用到類

是從裏到外的執行順序。

元數據

reflect-metadata 庫是來支持實驗性的metadata API,這個庫還不是ECMAScript (JavaScript)標準的一部分。

要使用元數據須要先開啓experimentalDecorators emitDecoratorMetadata選項。

當啓用後,只要reflect-metadata庫被引入了,設計階段添加的類型信息能夠在運行時使用。

function D(...rest) {

}

class A {
  @D
  readonly a: string;
}

class B {
  fn(@D x: A) {
    console.log(x)
  }
}
複製代碼

會被轉義成

function D(...rest) {
}
class A {
}
__decorate([
    D,
    __metadata("design:type", String)
], A.prototype, "a", void 0);
class B {
    fn(x) {
        console.log(x);
    }
}
__decorate([
    __param(0, D),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [A]),
    __metadata("design:returntype", void 0)
], B.prototype, "fn", null);
複製代碼

它加入了__metadata函數,將裝飾器的元信息存取起來,這樣就能夠隨時獲取出來。

nodejs 的 nestjs 框架就大量使用到了這些元信息。

相關文章
相關標籤/搜索