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