Decorator 簡介及實戰

hflk6888 7年前發布 | 22K 次閱讀 JavaScript開發 JavaScript

前言

用過Java的朋友都知道,裝飾器(Decorator)是一種十分非常方便改變類運行是行為的一種方式,例如在 Spring 框架中我們用到比較多的注解(@Autowired), 通過它可以自動實例化對象,從而可以精簡代碼。裝飾器是典型的 AOP(Aspect-Oriented-Programming) 編程的應用,類似的 CSS 對于 HTML 的樣式也是類似于這種思想,即從切面來改變和影響主對象的行為。

Decorator 簡介

Decorator 是一種通過注解表達式就可以擴展類或者方法的函數。Decorator 可以應用到任何一個 class 或者property 上。列如:

@myDecorator class A {} // 作用class

@myDecorator doSomething() {} // 作用表達式</pre>

Javascript Decorator 目前任然是ES7提案狀態,更多該特性的進度可以訪問 proposal-decorators 查看。

Decorator原理

說到更改對象的屬性或者方法,大家肯定會想到 Object.defineProperty(obj, prop, descriptor) 方法,通過該方法,我們可以輕易的修改或者重寫對象的行為或者屬性,之前 Vue 中提到的雙向綁定,即是通過重寫 set 和 get 方法來實現的。所以在我們還未正式用上 Decorator 前,都是通過 Object.defineProperty 方法來實現。先來簡單的認識下這個方法:

/**

  • obj : 需要修改屬性的對象
  • prop : 需要修改對象的屬性名稱
  • descriptor: 用來定義屬性具體行為的描述對象
    **/
    Object.defineProperty(obj, prop, descriptor)

descriptor 屬性說明

  • configurable : 定義屬性對象是否可以被配置,即如果為 false ,定義修改的描述操作(writeable, get 等等)都無效

  • enumerable : 是否可以通過 for-in 來遍歷,或者 Object.keys 列舉

  • value : 定義對象 value 屬性的值,value 可以是 number, object, function 等等

  • writable: 定義 value 值是否可以被重寫

  • get: 一個訪問 value 屬性時會觸發的 function 對象

  • set: 一個設置 value 屬性時會觸發的 function 對象

修改一個屬性為只讀(readonly)

了解 Object.defineProperty 的基本語法后,我通過它先簡單實現一個 readonly 實例。具體代碼如下:

Decorator 的基本語法與使用

``javascript

定義

function myDecoration(target, name, descriptor) {}

對property使用

class A { @myDecorator test() {} }

對class使用

@myDecorator class A {}

帶參數

function myDescorator(a) { return function (target, name, descriptor) { console.llog('params:', a) } } @myDescorator(a) class A {}

時使用多個裝飾器(Decorator)

@myDecorator1 @myDecorator2 class A {}</pre>

利用 Decorator 語法糖修改一個屬性為只讀(readonly)

利用 Decorator 給 React 組件封裝 PureRender

我們都知道,在 React 生命周期里有一個 shouldComponentUpdate 方法,該方法通過返回 ture 或者 false 來確定組件是否重新 render 組件。也就是說,通過該方法我們可以過濾掉些無效的數據渲染事件,從而提升性能。例如我們針對 props 傳遞過來的數據對象進行對比,如果 props 對象的屬性以及值并未變更的情況下,則無需執行render方法。

顯然通過對比 props 下數據對象的屬性與值是否變更,這種邏輯是可以復用的,而不是在單獨的在每個組件中去在重復的寫 shouldComponentUpdate 方法。說到改變組件對象的方法行為,這里我們顯然就可以使用

Decorator 來這個特性來做了,即我們對應用 Decorator 對象的 shouldComponentUpdate 進行重寫。通過遍歷 props 對象的屬性和值,并與老 props 的屬性與值進行對比,從而確定是否需要重新渲染。具體代碼如下:

function isEqual(a, b) {
  for (const key in a) {
    if ({}.hasOwnProperty.call(a, key) &&
      (!{}.hasOwnProperty.call(b, key) || a[key] !== b[key])) {
      return false;
    }
  }
  for (const key in b) {
    if ({}.hasOwnProperty.call(b, key) && !{}.hasOwnProperty.call(a, key)) {
      return false;
    }
  }
  return true;
}

export default function pureRender(targetComponent) { targetComponent.prototype.shouldComponentUpdate = function (props, state) { return !isEqual(this.state, state) || !isEqual(this.props, props) } }

// 使用 @pureRender class ComponentA extends React.Component {}</pre>

通過 Babel 使用 Decorator

由于 Decorator 是ES7中的草案,所以現在需要通過 Bable 才能使用。使用方法如下:

安裝

npm install --save-dev babel-plugin-transform-decorators

使用

方法一、 通過配置.babelrc

{
  "plugins": ["transform-decorators"]
}

方法二、通過CLI

babel --plugins transform-decorators script.js

方法三、通過Node API

require("babel-core").transform("code", {
  plugins: ["transform-decorators"]
});

總結

通過 Decorator 這種不需要直接在對象或者方法中編寫額外邏輯的方式,就可以輕易的擴展對象或者方法的能力,既滿足了功能需求,也精簡了代碼,保證了代碼的可維護性,例如我們已經常見的@log, @test, @mixin等等工具類。所以,以后的工作中可以多多嘗試。

 

參考

 

來自:http://div.io/topic/2063

 

 本文由用戶 hflk6888 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!