React Native面向切面編程

React Native:面向切面編程 && JavaScript ES7修飾符javascript

編譯期類加載期運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。AOP其實只是OOP的補充而已。OOP從橫向上區分出一個個的類來,而AOP則從縱向上向對象中加入特定的代碼。有了AOP,OOP變得立體了。若是加上時間維度,AOP使OOP由原來的二維變爲三維了,由平面變成立體了。從技術上來講,AOP基本上是經過代理機制實現的。 AOP在編程歷史上能夠說是里程碑式的,對OOP編程是一種十分有益的補充。 應用:將通用行的代碼,在不污染其餘功能代碼的前提下,更好的複用java

ES7修飾器

參考文檔1:讀懂ES7中javascript修飾器 參考文檔2:JavaScript 修飾符是什麼及什麼時候使用它們
參考文檔3:ECMAScript 6 入門webpack

什麼是修飾器

這個概念你之前可能據說過,就是「功能組合」,或者「高階函數」。修飾器(Decorator)是ES7的一個提案,它的出現能解決兩個問題:es6

  • 不一樣類間共享方法
  • 編譯期對類和方法的行爲進行改變

怎麼使用 JavaScript 修飾符?

修飾符使用一個在 ES2017 中定義的特殊語法,在被修飾的代碼前放置一個 @ 開頭的符號。web

爲何使用修飾符?

JavaScript 中已經能夠實現功能組合,但明顯比較困難 —— 甚至不可能 —— 把相同的技術應用到其它代碼上(好比類和類屬性)。npm

ES2017 草案添加了支持類和屬性的修飾符,它能夠用來解決這些問題,未來的 JavaScript 版本可能會容許在其它棘手的代碼區域添加修飾符。編程

修飾符的不一樣類型

目前,惟一支持的修飾類型是用在類和類成員上的,包括屬性、方法、getters 和 setters。json

修飾符只不過是返回另外一個函數的函數,這被稱爲被修飾項適當的細節。這些修飾符函數會在程序首次運行時被執行一次,而其返回值會替代被修飾的代碼。segmentfault

類成員修飾符

類修飾符

例子1:修飾類

@setProp
class User {}
function setProp(target) {
    target.age = 30
}
console.log(User.age)
複製代碼

這個例子要表達的是對User類使用setProp這個方法進行修飾,用來增長User類中age的屬性,setProp方法會接收3個參數,咱們如今接觸第一個,target表明User類自己。bash

例子2:修飾類(自定義參數值)

@setProp(20)
class User {}
function setProp(value) {
    return function (target) {
        target.age = value
    }
}
console.log(User.age)
複製代碼

此例和上面功能基本一致,惟一差異在於值是參考修飾函數傳過來的

例子2:修飾方法

class User {
    @readonly
    getName() {
        return 'Hello World'
    }
}

// readonly修飾函數,對方法進行只讀操做
function readonly(target, name, descriptor) {
    descriptor.writable = false
    return descriptor
}

let u = new User()
// 嘗試修改函數,在控制檯會報錯
u.getName = () => {
    return 'I will override'
}
複製代碼

上例中,咱們對User類中的getName方法使用readonly修飾器進行修飾,使得方法不能被修改。第一個參數咱們已經知道了,參數name爲方法名,也就是readonly,參數descriptor是個啥東西呢,看到這行descriptor.writable = false,咱們你們猜的也差很少了,這三個參數對應的就是Object.defineProperty的三個參數,咱們來看一下:

咱們設置 descriptor.writable = false就是讓函數不能夠被修改,若是咱們寫成 descriptor.value = 'function (){ console.log('Hello decorator') }'那麼,輸出就是 Hello World了,而是 Hello decorator,是否是已經意識到修飾器的好處了。如今咱們來看看實際工做中,咱們用到修飾器的例子

實際應用1:日誌管理

咱們常常在每一步打印一些日誌文件,好比這步都幹了些什麼事,很明顯打印日誌的操做和業務代碼根本就一點關係沒有,咱們不該該把日誌和業務摻和在一塊兒,這樣使用修飾器就是避免這個問題,如下爲代碼:

class Pack {
    @log('讀取package.json文件')
    step1() {
        // do something...
        // 沒有修飾器以前,咱們一般把console.log放到這裏寫
        // 放到函數裏面寫會有兩個壞處
        //     1.console和業務無關,會破壞函數單一性原則
        //     2.若是要刪除全部的console,那咱們只能深刻到每個方法中
    }
    @log('合併webpack配置文件')
    step2() {
        // do something...
    }
}

function log(value) {
    return function (target, name, descriptor) {
        // 在這裏,咱們還能夠拿到函數的參數,打印更加詳細的信息
        console.log(value)
    }
}

let pack = new Pack()
pack.step1()
pack.step2()
複製代碼

實際應用2:檢查登陸

在實際的開發中經常使用獲得,咱們一些操做前,必須得判斷用戶是否登陸,比較點贊、結算、發送彈幕...按照以前的寫法,咱們必須在每個方法中判斷用戶的登陸狀況,而後再進行業務的操做,很顯然前置條件和業務又混到了一塊兒,用修飾器,就能夠完美的解決這一問題,代碼以下:

class User {
    // 獲取已登陸用戶的用戶信息
    @checkLogin
    getUserInfo() {
        /**
         * 以前,咱們都會這麼寫:
         *      if(checkLogin()) {
         *          // 業務代碼
         *      }
         *  這段代碼會在每個須要登陸的方法中執行
         *  仍是上面的問題,執行的前提和業務又混到了一塊兒
         */
        console.log('獲取已登陸用戶的用戶信息')
    }
    // 發送消息
    @checkLogin
    sendMsg() {
        console.log('發送消息')
    }
}

// 檢查用戶是否登陸,若是沒有登陸,就跳轉到登陸頁面
function checkLogin(target, name, descriptor) {
    let method = descriptor.value

    // 模擬判斷條件
    let isLogin = true

    descriptor.value = function (...args) {
        if (isLogin) {
            method.apply(this, args)
        } else {
            console.log('沒有登陸,即將跳轉到登陸頁面...')
        }
    }
}
let u = new User()
u.getUserInfo()
u.sendMsg()
複製代碼

實際應用3:定時器

普通寫法:

setTimeout(() => {
  this.fn();
}, 0);
複製代碼

修飾符寫法:

@timeout(1000)
fn() {
  // doing
}

this.fn();
複製代碼

對應的 timeout 修飾器代碼:

// timeout.ts
export function timeout(milliseconds: number = 0) {
  return function(target, key, descriptor) {
    // value 值至關於上面示例中 `change` 方法。
    var orgMethod = descriptor.value;
    descriptor.value = function(...args) {
      setTimeout(() => {
        orgMethod.apply(this, args);
      }, milliseconds);
    };
    return descriptor;
  }
}
複製代碼
  • target:實例對象,即 IndexComponent 實例化對象。
  • key:方法名稱,即 fn。
  • descriptor:對象描述,同Object.getOwnPropertyDescriptor() 。

實際應用4:Core 修飾符

有一個神奇的庫,稱爲 Core Decorators,它提供一些日常有用的修飾符。

這些修飾符使用簡潔的語法,提供了很是有用的通用功能(好比,調用方法的時候,否決警告,容許某個值只讀等)。

實際應用5:React

React 庫很好的利用了高階組件(Higher-Order Components)的概念。React 組件能夠簡單的寫成函數,而它能夠包含另外一個組件。

實際應用6:MobX

MobX 庫普遍使用了修飾符,讓你很容易把字段標記爲 Observable(可觀察對象) 或 Computed(計算屬性),以及把類變成 Observers(觀察者)。

結語: 只要咱們涉及須要在執行前作一些處理的應用,不論是修改函數的參數值,仍是增長屬性,仍是執行的先決條件,咱們均可以使用修飾器,這種編程的方式,就是面對切面編程

相關文章
相關標籤/搜索