摘要:修改配置遠比修改源代碼要簡單的多。在年提出了種設計模式。常用的設計模式及設計原則可以參考下面的思維導圖。每種設計模式都有它的適應場景,有的場景也會使用多種設計模式。包含文章視頻源代碼原創新書移動前端高效開發實戰已在亞馬遜京東當當開售。
作者:曉飛
本文原創,轉載請注明作者及出處
在后端語言中,設計模式應用的較為廣泛。如Spring中常見的工廠模式、裝飾者模式、單例模式、迭代器模式。但是在日常的前端開發中,設計模式使用的較少,或者大家的代碼已經遵循了某某設計模式但是我們并不知道。常見的設計模式有23種,如果單純的按照模式名稱+名詞解釋的方式來寫這篇文章,可能太枯燥了或者很難理解記憶,所以我打算換一種方式。下面我們以一個例子開始我們今天的文章。
let page = { init: ()=>{ //此處(placeA)有很多業務代碼或者調用了很多page中的其他初始化函數 }, .... };
現在業務迭代,需要我們在page.init()初始化代碼塊的最后增加一些功能,同時不影響原先的功能。按照正常的寫法,我們可能會像下面這樣寫:
let page = { init: ()=>{ //placeA page.newFunction(); }, newFunction: ()=>{ ... } };
這樣寫是可以解決我們的需求,但是這樣的代碼是具有侵略性的,我們不得不在原先的代碼的合適位置新增我們需要的代碼。但我們思考一個問題,如果我們用了某個插件或者某個被ungly、minify之后的代碼呢,我們怎么在找到合適的位置添加我們需要的功能呢?大家可以先自己思考一下,再看下面的內容。
//我們可以在Function的原型鏈上定義一個擴展函數,以實現我們的需求。 Function.prototype.fnAfter = function(fn) { var _self = this; return function() { _self.apply(this, arguments); fn.apply(this, arguments); } }; page.init = (page.init || function() {}).fnAfter(function() { console.log("我們要追加的功能成功啦~"); }); page.init();
上面的代碼已經能夠實現我們的需要了,但是其實還是不夠好或者可以寫的更靈活一些。因為我希望可以可以做到像jquery的鏈式調用那樣,可以一直往后面追加新的功能。那么我們在上面代碼的基礎上再擴展下,其實很簡單,我們只要再Function.prototype.fnAfter中再返回自身就好了。
Function.prototype.fnAfter = function(fn) { var _self = this; return function() { var fnOrigin = _self.apply(this, arguments); fn.apply(this, arguments); return fnOrigin; } };
其實上面的代碼寫法還是可以優化的。比如:
//每次擴展的時候我們都需要這么寫 page.init = (page.init || function() {}).fnAfter(function() { //... }); //我們能不能再優化下,比如容錯代碼 || function(){} 在一個地方統一處理 //或者我們新建一個工廠函數來幫我們統一做這樣的事情,這里我們就不展開了,文章篇幅有限。
有的時候我們通過擴展來提高代碼的靈活性并不能解決所有的場景需要,在不可避免發生修改的時候,我們可以通過增加配置文件,讓用戶修改配置文件以實現個性化需求也是合理的。修改配置遠比修改源代碼要簡單的多。
單例模式
單例模式顧名思義:保證一個類僅有一個實例, 并且對外暴露一個能夠訪問到它的訪問點。
實現單例模式的核心就是保證一個類僅有一個實例,那么意思就是當創建一個對象時,我們需要判斷下之前有沒有創建過該實例,如果創建過則返回之前創建的實例,否則新建。
var fn = function() { this.instance = null; }; fn.getInstance = function() { //寫法1 if (!this.instance) { this.instance = new fn(); } return this.instance; //寫法2 return this.instance || (this.instance = new fn()); }; var fnA = fn.getInstance(); var fnB = fn.getInstance(); console.log(fnA === fnB); //true
日常的業務場景中,單例模式也比較常見,比如:一個頁面中的模態框只有一個,每次打開與關閉的都應該是同一個,而不是重復新建。而且為了性能優化,我們應該在需要時再創建,而不是頁面初始化時就已經存在于dom中,這個就是惰性單例模式。
//假設我們需要點擊某個按鈕時就顯示出模態框,那么我們可以像下面這么實現。 var createModal = (function(){ var modal = null; return function() { if (!modal) { modal = document.createElement("div"); //... modal.style.display = "none"; document.getElementById("container").append(modal); } return modal; } })(); document.getElementById("showModal").click(function() { var modal = createModal(); modal.style.display = "block"; });
上面的代碼中,我們將創建對象和管理實例的邏輯都放在一個地方,違反了單一職責原則,我們應該多帶帶新建一個用于創建單例的方法,這樣我們不僅能創建唯一的modal實例,也能創建其他的,職責分開。
var createSingleInstance = function(fn) { var instance = null; return function() { if (!instance) { instance = fn.apply(this, arguments); } return instance; } }; var createModal = function() { var modal = docuemnt.createElement("div"); //... modal.style.display = "none"; document.getElementById("container").append(modal); return modal; }; var modal = createSingleInstance(createModal);
?
觀察者模式
定義了對象與其他對象之間的依賴關系, 當某個對象發生改變的時候,所有依賴到這個對象的地方都會被通知。
像knockout.js中的ko.compute以及vue中的computed函數其實就是這個模式的實踐。實現觀察者模式的核心就是我們需要有一個變量來保存所有的依賴,一個listen函數用于向變量中添加依賴,一個trigger函數用于觸發通知。
var observal = { eventObj: {}, listen: function(key, fn) { this.eventObj[key] = this.eventObj[key] || []; this.eventObj[key].push(fn); }, trigger: function(key) { var eventList = this.eventObj[key]; if (!eventList || eventList.length < 1) { return; } var length = eventList.length; for (var i = 0; i < length; i++) { var event = eventList[i]; event.apply(this, arguments); } } }; //定義要監聽的事件 observal.listen("command1", function() { console.log("黑夜給了我夜色的眼睛~"); }); observal.listen("command1", function() { console.log("我卻用它尋找光明~"); }); observal.listen("command2", function() { console.log("一花一世界~"); }); observal.listen("command2", function() { console.log("一碼一人生~"); }); //觸發某個監聽的事件 observal.trigger("command1");//黑夜給了我夜色的眼睛~ 我卻用它尋找光明~ observal.trigger("command2");//一花一世界~ 一碼一人生~
使用觀察者模式(發布-訂閱模式)我們可以使得代碼更靈活、健壯性更高。訂閱者不需要了解消息來自哪一個發布者,發布者也不需要知道消息會發送給哪些訂閱者。
同樣的我們可以創建一個公用的函數庫,里面存放創建observal的工具方法,需要用到的地方我們就用這個方法創建一個發布訂閱對象。
其他設計模式及設計原則
設計模式有很多,這里篇幅有限就不再展開。GoF在1995年提出了23種設計模式。諸如策略者模式優化表單驗證、代理模式、組合模式、裝飾者模式、適配器模式...這些后期可以再簡單探討或者大家后面自己了解。常用的設計模式及設計原則可以參考下面的思維導圖。 ![常用設計模式](https://user-gold-cdn.xitu.io/2017/10/27/f7ab0664b5fd4e34dbb16eaab5813c9d) ![六大設計原則](https://user-gold-cdn.xitu.io/2017/10/27/038d561c77aba1ff095fa0c3cfc8c113)
設計模式都是經過了大量的代碼、軟件實踐而總結出來的優秀的組織實踐方案。每種設計模式都有它的適應場景,有的場景也會使用多種設計模式。只有了解了更多的設計模式,掌握各個設計模式自己的適應場景,才能更好的為我們所用。
但是過早的優化不一定是好事或者不是必須的,有時候我們可以一開始并不去優化,等到某個應用場景下出現了代碼組織混亂、需要額外擴展等問題,我們再優化重構,以防過早優化導致的不必要性或者只是增加了代碼不必要的復雜性。就像redux,如果一個頁面組件與組件之間有數據共享、需要在任意組件內部拿到某個數據、任意一個組件中某個行為導致的數據變化需要通知到所有用到的地方,那么這個時候可以使用redux,一些簡單的表單頁面或者展示頁完全可以不用redux。
從前有只麋鹿,它在森林里玩兒,不小心走丟了。 于是它給它的好朋友長頸鹿打電話:“喂…我迷路辣。” 長頸鹿聽見了回答說:“喂~我長頸鹿辣~”
參考:曾探《javascript設計模式與開發實踐》
---
iKcamp官網:http://www.ikcamp.com
訪問官網更快閱讀全部免費分享課程:《iKcamp出品|全網最新|微信小程序|基于最新版1.0開發者工具之初中級培訓教程分享》。
包含:文章、視頻、源代碼
iKcamp最新活動iKcamp原創新書《移動Web前端高效開發實戰》已在亞馬遜、京東、當當開售。
報名地址:http://www.huodongxing.com/ev...
與“天天練口語”小程序總榜排名第四、教育類排名第一的研發團隊,面對面溝通交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89345.html
摘要:工程實踐立足實踐,提示實際水平內聯函數與性能很多關于性能優化的文章都會談及內聯函數,其也是常見的被詬病為拖慢性能表現的元兇之一不過本文卻是打破砂鍋問到底,論證了內聯函數并不一定就會拖慢性能,過度的性能優化反而會有損于應用性能。 showImg(https://segmentfault.com/img/remote/1460000011481413?w=1240&h=825); 前端每周...
摘要:發布本周正式發布,包含了一系列的特性提升與問題修復,同時也在不斷致力于將打造地更為輕巧與高性能。當然,姜振勇老師還會介紹的多種服務,包括大數據網絡和安全,展現彈性安全和高可擴展性的全方位能力。 showImg(http://upload-images.jianshu.io/upload_images/1647496-2ce7598e6987d9af.jpg?imageMogr2/aut...
摘要:作者眾成翻譯只寫的禪眾成翻譯如何使更高效如何用構建前端架構小米直達服務介紹與開發實戰搭建一個多頁面的無依賴的工程化項目掘金計算機網絡概念和結構掘金英文 2017-10-29 前端日報 精選 【譯】圖與例解讀Async/AwaitVue + TypeScript 新項目起手式 React-Router動態路由設計最佳實踐Vue2 原理淺談使用合適的設計模式一步步優化前端代碼The 14 ...
摘要:前端每周清單第期與模式變遷與優化界面生成作者王下邀月熊編輯徐川前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。 showImg(https://segmentfault.com/img/remote/1460000013279448); 前端每周清單第 51 期: React Context A...
閱讀 3573·2021-10-11 10:59
閱讀 1591·2021-09-29 09:35
閱讀 2259·2021-09-26 09:46
閱讀 3771·2021-09-10 10:50
閱讀 953·2019-08-29 12:17
閱讀 821·2019-08-26 13:40
閱讀 2433·2019-08-26 11:44
閱讀 2103·2019-08-26 11:22