JavaScript裝飾器的使用

Ruios發表於2018-12-20

隨著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是一個裝飾器生成器函式,返回一個修飾類方法的裝飾器,該裝飾器的三個引數分別是: 該屬性的原型,屬性名,和屬性描述物件。最後,屬性裝飾器必須有返回值,返回值是該屬性的描述物件。

相關文章