隨著ES6的廣泛使用,class 類的概念在javascript中出現,而在某些場景下,需要在不改變類或者類的屬性的情況下擴充套件一些功能,於是裝飾器出現了。
裝飾器簡介
在類或類屬性之前加上@... 用於對類或累的屬性進行一些功能注入,類似Java裡的註解
作用於類的裝飾器
當裝飾器作用於類時
@log
class MyClass { }
function log(target) { // 這個 target 在這裡就是 MyClass 這個類
target.prototype.logger = () => `${target.name} 被呼叫`
}
const test = new MyClass()
test.logger() // MyClass 被呼叫
複製程式碼
可以看到:裝飾器實質上是一個函式,此時函式引數target是被裝飾類本身。log裝飾器作用在MyClass上,在其原型在新增了一個logger方法,使得其所有例項都可以呼叫該方法。
在很多場景下,我們使用的裝飾器可以傳參,這是裝飾器生成函式。
@log('hi')
class MyClass { }
// 定義裝飾器
function log(text) {
return function(target) {
target.prototype.logger = () => `${text},${target.name} 被呼叫`
}
}
複製程式碼
在react-redux中在使用connent時也是這樣:
@connect(mapStateToProps, mapDispatchToProps)
export default class MyComponent extends React.Component {}
複製程式碼
作用於類屬性的裝飾器
與裝飾類不同,裝飾類屬性時,實質上是對屬性的描述符進行操作,類似於Object.defineProperty(obj, prop, descriptor),如下程式碼:
class MyClass {
@readonly(true) // 對屬性方法裝飾
method() { console.log('cat') }
}
// 裝飾器生成函式定義
function (value) {
// 這裡才是真正的裝飾器
return function (target, key, descriptor) {
descriptor.writable = !value
return descriptor
}
}
const instance = new MyClass()
instance.method = () => console.log('dog')
c.method() // cat
複製程式碼
可以看到,readonly是一個裝飾器生成器函式,返回一個修飾類方法的裝飾器,該裝飾器的三個引數分別是: 該屬性的原型,屬性名,和屬性描述物件。最後,屬性裝飾器必須有返回值,返回值是該屬性的描述物件。