最近在研讀一本書《JavaScript設計模式與開發實踐》,進階用的。
一、高階函數
高階函數是指至少滿足下列條件之一的函數。
1. 函數可以作為參數被傳遞。
2. 函數可以作為返回值輸出。
1)高階函數實現AOP
AOP(面向切面編程)的主要作用是把一些跟核心業務邏輯模塊無關的功能抽離出來,這些跟業務邏輯無關的功能通常包括日志統計、安全控制、異常處理等。
把這些功能抽離出來之后,再通過“動態織入”的方式摻入業務邏輯模塊中。
這樣做的好處首先是可以保持業務邏輯模塊的純凈和高內聚性,其次是可以很方便地復用日志統計等功能模塊。
在 JavaScript 中實現 AOP,都是指把一個函數“動態織入”到另外一個函數之中,查看demo。
Function.prototype.before = function( beforefn ){ var __self = this; // 保存原函數的引用 return function(){ // 返回包含了原函數和新函數的"代理"函數 beforefn.apply( this, arguments ); // 執行新函數,修正 this return __self.apply( this, arguments ); // 執行原函數 } }; Function.prototype.after = function( afterfn ){ var __self = this; return function(){ var ret = __self.apply( this, arguments ); afterfn.apply( this, arguments ); return ret; } }; var func = function(){ console.log( 2 ); }; func = func.before(function(){ console.log( 1 ); }).after(function(){ console.log( 3 ); }); func();//1 2 3
2)currying
函數柯里化(function currying)又稱部分求值。
一個 currying 的函數首先會接受一些參數,接受了這些參數之后,該函數並不會立即求值,而是繼續返回另外一個函數,剛才傳入的參數在函數形成的閉包中被保存起來。
待到函數被真正需要求值的時候,之前傳入的所有參數都會被一次性用於求值。簡單點說就是返回一個函數。demo查看:
var cost = (function() { var args = []; return function() { if (arguments.length === 0) { var money = 0; for (var i = 0, l = args.length; i < l; i++) { money += args[i]; } return money; } else { [].push.apply(args, arguments); } } })(); cost(100); // 未真正求值 cost(200); // 未真正求值 cost(300); // 未真正求值 console.log(cost()); // 求值並輸出:600
二、設計模式
1)單例模式
定義:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
單例模式的核心是確保只有一個實例,並提供全局訪問。
惰性單例。
2)策略模式
定義是:定義一系列的算法,把它們一個個封裝起來,並且使它們可以相互替換。
這句話如果說得更詳細一點,就是:定義一系列的算法,把它們各自封裝成策略類,算法被封裝在策略類內部的方法里。在客戶對 Context 發起請求的時候,Context 總是把請求委托給這些策略對象中間的某一個進行計算。
計算獎金、緩動動畫、表單校驗。
3)代理模式
代理模式是為一個對象提供一個代用品或占位符,以便控制對它的訪問。
代理模式的關鍵是,當客戶不方便直接訪問一個對象或者不滿足需要的時候,提供一個替身對象來控制對這個對象的訪問,客戶實際上訪問的是替身對象。替身對象對請求做出一些處理之后,再把請求轉交給本體對象。
保護代理和虛擬代理,虛擬代理實現圖片預加,緩存代理,用高階函數動態創建代理。
4)迭代器模式
迭代器模式是指提供一種方法順序訪問一個聚合對象中的各個元素,而又不需要暴露該對象的內部表示。迭代器模式可以把迭代的過程從業務邏輯中分離出來,在使用迭代器模式之后,即使不關心對象的內部構造,也可以按順序訪問其中的每個元素。
內部迭代器和外部迭代器,
5)發布—訂閱模式
發布—訂閱模式又叫觀察者模式,它定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都將得到通知。
DOM事件, 自定義事件,通用實現。
6)命令模式
命令模式中的命令(command)指的是一個執行某些特定事情的指令。
命令模式最常見的應用場景是:有時候需要向某些對象發送請求,但是並不知道請求的接收者是誰,也不知道被請求的操作是什么。
此時希望用一種松耦合的方式來設計程序,使得請求發送者和請求接收者能夠消除彼此之間的耦合關系。
菜單程序,撤消命令,命令隊列。
7)組合模式
組合模式將對象組合成樹形結構,以表示“部分-整體”的層次結構。
除了用來表示樹形結構之外,組合模式的另一個好處是通過對象的多態性表現,使得用戶對單個對象和組合對象的使用具有一致性。
宏命令,掃描文件夾。
8)模板方法模式
模板方法模式是一種只需使用繼承就可以實現的非常簡單的模式。
模板方法模式由兩部分結構組成,第一部分是抽象父類,第二部分是具體的實現子類。
在模板方法模式中,子類實現中的相同部分被上移到父類中,而將不同的部分留待子類來實現。這也很好地體現了泛化的思想。
Coffee or Tea,鈎子方法,好萊塢原則。
9)享元模式
享元(flyweight)模式是一種用於性能優化的模式,“fly”在這里是蒼蠅的意思,意為蠅量級。
享元模式的核心是運用共享技術來有效支持大量細粒度的對象。
通用結構,通用對象池。
10)職責鏈模式
職責鏈模式的定義是:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系,將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它為止。
職責鏈的實現,用AOP實現職責鏈
11)中介者模式
中介者模式的作用就是解除對象與對象之間的緊耦合關系。增加一個中介者對象后,所有的相關對象都通過中介者對象來通信,而不是互相引用,所以當一個對象發生改變時,只需要通知中介者對象即可。
泡泡堂。
12)裝飾者模式
裝飾者模式可以動態地給某個對象添加一些額外的職責,而不會影響從這個類中派生的其他對象。
飛機大戰,裝飾函數,用AOP 裝飾函數 。
13)狀態模式
允許一個對象在其內部狀態改變時改變它的行為,對象看起來似乎修改了它的類。
第一部分的意思是將狀態封裝成獨立的類,並將請求委托給當前的狀態對象,當對象的內部狀態改變時,會帶來不同的行為變化。
第二部分是從客戶的角度來看,我們使用的對象,在不同的狀態下具有截然不同的行為,這個對象看起來是從不同的類中實例化而來的,實際上這是使用了委托的效果。
通用結構,文件上傳,JavaScript 版本的狀態機。
14)適配器模式
適配器模式主要用來解決兩個已有接口之間不匹配的問題,它不考慮這些接口是怎樣實現的,也不考慮它們將來可能會如何演化。
適配器模式不需要改變已有的接口,就能夠使它們協同作用。
