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 多個裝飾器執行順序是,
是從裏到外的執行順序。
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 框架就大量使用到了這些元信息。