一篇記錄了本身思考的讀書筆記。
博客:Murphy 的博客
知乎:@Murphygit
面向側面的程序設計(aspect-oriented programming,AOP,又譯做面向方面的程序設計、觀點導向編程、剖面導向程式設計)是計算機科學中的一個術語,指一種程序設計範型。該範型以一種稱爲側面(aspect,又譯做方面)的語言構造爲基礎,側面是一種新的模塊化機制,用來描述分散在對象、類或函數中的橫切關注點(crosscutting concern)。github
從編程的角度看,在運行時,動態地將代碼切入到類的指定方法、指定位置的編程思想就是面向切面編程。編程
AOP 的主要做用是把一些跟核心業務邏輯模塊無關的功能抽離出來,這些跟業務邏輯無關的功能一般包括日誌統計、安全控制、異常處理等。這樣作的好處首先是能夠保持業務邏輯模塊的純淨和高內聚性,其次是能夠很方便地複用日誌統計等功能模塊。設計模式
從主關注點中分離出橫切關注點是面向側面的程序設計(aspect-oriented programming)的核心概念。分離關注點使得解決特定領域問題的代碼從業務邏輯中獨立出來,業務邏輯的代碼中再也不含有針對特定領域問題代碼的調用,業務邏輯同特定領域問題的關係經過側面來封裝、維護,這樣本來分散在在整個應用程序中的變更就能夠很好的管理起來。瀏覽器
在 Java 語言中,能夠經過反射和動態代理實現 AOP 技術,而在 JavaScript 中,有一種很是巧妙的方法實現。咱們先來看一下想要達到的效果:安全
原來的函數長這樣(能夠把它看做核心業務邏輯):app
var func = function() {
console.log(2);
}複製代碼
如今呢,想改造一下這個函數,把某些但願在把這個函數以前執行和以後執行的函數「動態織入」到核心函數中,像這樣:模塊化
func = func.before(function() {
// 在 func 執行以前執行的函數
}).after(function() {
// 在 func 執行以後執行的函數
})複製代碼
而後再執行 函數
func();複製代碼
時,可以依次執行 before()
傳入的函數,func()
原來的內容,最後是 after()
傳入的函數。怎麼作到呢?測試
首先,函數可以鏈式執行下去意味着任何函數(或者其原型鏈上)都有對 before
和 after
的定義,所以能夠擴充函數的構造函數(Function
) 的原型(prototype
)。而後爲了能按照咱們但願的順序執行,須要調整 func()
自己的內容在執行過程當中的順序。咱們知道在 JavaScript 中,除了直接執行一個函數外,還可使用 call
或者 apply
執行,好比:
var foo = function(str) {
console.log(str);
}
foo("hello"); // hello
foo.call(this, "hello"); // hello
foo.apply(this, ["hello"]); // hello複製代碼
因此呢,是否是能夠這樣子,爲了在執行核心函數 func
以前動態織入 before
中的函數,能夠先保存對 func
的引用,並在以後返回一個規定好執行順序的裝飾後的函數。像這樣:
Function.prototype.before = function(beforefn) {
var _self = this; // 保存對原函數的引用
return function() {
beforefn.apply(this, arguments);
_self.apply(this, arguments);
}
}複製代碼
注意這句 _self = this
的做用,由於咱們調用 before
時會做爲核心函數的方法調用,因此第一個 this
會是核心函數自己;而在返回的函數中,this
就無所謂了,它指向的是全局變量,在瀏覽器中的話就是 window
。
來驗證一下:
func = func.before(function() {
console.log(1);
})
func(); // 1 2複製代碼
Success √
因此 after
的寫法也相似:
Function.prototype.after = function(afterfn) {
var _self = this;
return function() {
_self.apply(this, arguments);
afterfn.apply(this, arguments);
}
}複製代碼
仍是同樣測試一下:
func = func.after(function() {
console.log(3);
})
func(); // 2 3複製代碼
也能夠鏈式調用起來:
func = func.before(function() {
console.log(1);
}).after(function() {
console.log(3);
})
func(); // 1 2 3複製代碼
這種使用 AOP 的方式來給函數動態的添加職責,也是 JavaScript 語言中一種特別和巧妙的裝飾者模式實現。
參考: