React Native:面向切面編程 && JavaScript ES7修飾符javascript
在編譯期
、類加載期
、運行時
,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。AOP其實只是OOP的補充而已。OOP從橫向上區分出一個個的類來,而AOP則從縱向上向對象中加入特定的代碼。有了AOP,OOP變得立體了。若是加上時間維度,AOP使OOP由原來的二維變爲三維了,由平面變成立體了。從技術上來講,AOP基本上是經過代理機制
實現的。 AOP在編程歷史上能夠說是里程碑式的,對OOP編程是一種十分有益的補充。 應用:將通用行的代碼,在不污染其餘功能代碼的前提下,更好的複用java
參考文檔1:讀懂ES7中javascript修飾器 參考文檔2:JavaScript 修飾符是什麼及什麼時候使用它們
參考文檔3:ECMAScript 6 入門webpack
這個概念你之前可能據說過,就是「功能組合
」,或者「高階函數
」。修飾器(Decorator
)是ES7的一個提案,它的出現能解決兩個問題:es6
修飾符使用一個在 ES2017 中定義的特殊語法,在被修飾的代碼前放置一個 @
開頭的符號。web
JavaScript 中已經能夠實現功能組合,但明顯比較困難 —— 甚至不可能 —— 把相同的技術應用到其它代碼上(好比類和類屬性)。npm
ES2017 草案添加了支持類和屬性的修飾符,它能夠用來解決這些問題,未來的 JavaScript 版本可能會容許在其它棘手的代碼區域添加修飾符。編程
目前,惟一支持的修飾類型是用在類和類成員上的,包括屬性、方法、getters 和 setters。json
修飾符只不過是返回另外一個函數的函數,這被稱爲被修飾項適當的細節。這些修飾符函數會在程序首次運行時被執行一次,而其返回值會替代被修飾的代碼。segmentfault
@setProp
class User {}
function setProp(target) {
target.age = 30
}
console.log(User.age)
複製代碼
這個例子要表達的是對User類使用setProp這個方法進行修飾,用來增長User類中age的屬性,setProp方法會接收3個參數,咱們如今接觸第一個,target表明User類自己。bash
@setProp(20)
class User {}
function setProp(value) {
return function (target) {
target.age = value
}
}
console.log(User.age)
複製代碼
此例和上面功能基本一致,惟一差異在於值是參考修飾函數傳過來的
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
,是否是已經意識到修飾器的好處了。如今咱們來看看實際工做中,咱們用到修飾器的例子
咱們常常在每一步打印一些日誌文件,好比這步都幹了些什麼事,很明顯打印日誌的操做和業務代碼根本就一點關係沒有,咱們不該該把日誌和業務摻和在一塊兒,這樣使用修飾器就是避免這個問題,如下爲代碼:
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()
複製代碼
在實際的開發中經常使用獲得,咱們一些操做前,必須得判斷用戶是否登陸,比較點贊、結算、發送彈幕...按照以前的寫法,咱們必須在每個方法中判斷用戶的登陸狀況,而後再進行業務的操做,很顯然前置條件和業務又混到了一塊兒,用修飾器,就能夠完美的解決這一問題,代碼以下:
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()
複製代碼
普通寫法:
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() 。有一個神奇的庫,稱爲 Core Decorators,它提供一些日常有用的修飾符。
這些修飾符使用簡潔的語法,提供了很是有用的通用功能(好比,調用方法的時候,否決警告,容許某個值只讀等)。
React 庫很好的利用了高階組件(Higher-Order Components)的概念。React 組件能夠簡單的寫成函數,而它能夠包含另外一個組件。
MobX 庫普遍使用了修飾符,讓你很容易把字段標記爲 Observable(可觀察對象) 或 Computed(計算屬性),以及把類變成 Observers(觀察者)。
結語: 只要咱們涉及須要在執行前作一些處理的應用,不論是修改函數的參數值
,仍是增長屬性
,仍是執行的先決條件
,咱們均可以使用修飾器
,這種編程的方式,就是面對切面編程