摘要:表單校驗創建一個對象獲取校驗結果代理模式為一個對象提供一個代用品或占位符,以便控制對它的訪問。當變化發生時,設計可能會到意外的。
紙上得來終覺淺,學習設計模式,看了很多書,但是始終還是覺得不如直接看例子來的更加客觀具體,下面主要記錄了js中的幾個常見的設計模式舉例,供自己以后復習的時候可以直接通過例子更快更好的理解設計模式。
單例模式保證一個類僅有一個實例,并提供一個全局訪問入口
var getSingleton = function(fn){ var result; return function(){ return result || (result = fn.apply(this, arguments)); } } var createLoginLayer = function(){ var div; return function(){ if(!div){ div = document.createElement("div"); div.innerText = "這是彈窗"; div.style.display = "none"; document.body.appendChild(div); } return div; } }); var singletonCreateLoginLayer = getSingleton(createLoginLayer); document.getElementById("loginBtn").onclick = function(){ var layer = singletonCreateLoginLayer(); layer.style.display = "block"; }策略模式
定義一系列算法,并使之可以相互替換。目的就是使算法的使用和定義分離出來。
var Strategy = { S: function(salary){ return salary * 4; }, A: function(salary){ return salary * 3; }, B: function(salary){ return salary * 2; } }; var getBouns = function(strategy, salary){ return Strategy[strategy](salary); } getBouns("B", 1000); // 2000
表單校驗
var strategies = { isNonEmpty: function(value, errorMsg){ .... }, minLength: function(value, length, errorMsg){ .... }, isMobile: function(value, errorMsg){ ... } }; var Validator = function(){ this.cache = []; }; Validator.prototype.add = function(dom, rule, errorMsg){ var ary = [rule]; this.cache.push(function(){ var strategy = ary.shift(); ary.unshift(dom.value); ary.push(errorMsg); return strategies[strategy].apply(dom, ary); }); } Validator.prototype.start = function(){ for(var i=0, validatorFunc; validatorFunc = this.cache[i++]){ var msg = validatorFunc(); if(msg){ return msg; } } } var validatorFunc = function(){ var validator = new Validator(); // 創建一個對象 validator.add(...); var errorMsg = validator.start(); // 獲取校驗結果 } var registerForm = document.getElementById("form"); registerForm.onsubmit = function(){ var errorMsg = validatorFunc(); if(errorMsg){ return false; } }代理模式
為一個對象提供一個代用品或占位符,以便控制對它的訪問。當客戶不方便直接訪問一個對象或者不滿足需要的時候提供一個替身對象來控制對這個對象的訪問,客戶實際上訪問的是替身對象。
單一職責原則指的是,就一個類(通常也包括對象和函數等)而言,應該僅有一個引起它變 化的原因。如果一個對象 了多 職責,就意味著這個對象將變得 大,引起它變化的原因可 能會有多個。面向對象設計 將行為分 到細 度的對象之中,如果一個對象 的職責過多, 等于把這些職責耦合到了一起,這種耦合會 致 和低內聚的設計。當變化發生時,設計可能 會 到意外的 。
虛擬代理圖片懶加載
const myImg = ( const node = documnet.createElement("img") document.body.appendChild(node) return { setSrc(src) { node.src= src } } )() const proxy = ( const img = new Image() img.onload = () => { myImg.setSrc(this.src) } return { setImg(src) { img.src = src myImg.setSrc("loading.gif") } } )()觀察者模式
發布訂閱模式又叫觀察者模式,它定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都將得到通知。在JavaScript開發中,我們一般用事件模型來替代傳統的發布訂閱模式。
const Event = ( function() { var eventList = {} var addEventListen var trigger var remove addEventListen = function(eventName, fn) { eventList[eventName] = eventList[eventName] || [] eventList[eventName].push(fn) } trigger = function() { var key = Array.prototype.shift.call(arguments) var fns = eventList[key] if (!fns || !fns.length) { return } fns.forEach((fn, index) => { fn.apply(this, arguments) }) } remove = function(eventName, fn) { var fns = eventList[eventName] if (!fns || !fns.length) { return false } if (!fn) { fns.length = 0 } else { fns.forEach((_fn, index) => { if(fn === _fn) { fns.splice(index, 1) } }) } } return { addEventListen, trigger, remove } } )() var testFn = () => { console.log("you have click a cancel btn") } Event.addEventListen("click", () => { console.log("you have click a button") }) Event.addEventListen("click", () => { console.log("you have click button2") }) Event.addEventListen("click", () => { console.log("you have click button3") }) Event.addEventListen("click", testFn) Event.remove("click", testFn) Event.trigger("click")享元模式
享元模式是為性能優化而生的,在一個存在大量相似對象的系統中,享元模式可以很好地解決大量對象帶來的性能問題
文件上傳// uploadType作為內部狀態,再抽離外部狀態 var Upload = function(uploadType){ this.uploadType = uploadType; }; // 定義刪除文件的方法 Upload.prototype.delFile = function(id){ uploadManager.setExternalState(id, this); // 設置外部狀態 if(this.fileSize < 3000){ return this.dom.parentNode.removeChild(this.dom); } if(window.confirm("確定要刪除文件嗎?"+ file.fileName)){ return this.dom.parentNode.removeChild(this.dom); } }; // 工廠進行對象實例化 var UploadFactory = (function(){ var createFlyWeightObjs = {}; return { create: function(uploadType){ if(createFlyWeightObjs[uploadType]){ return createFlyWeightObjs[uploadType]; } return createFlyWeightObjs[uploadType] = new Upload(uploadType); } } })(); // 管理器封裝外部狀態 var uploadManager = (function(){ var uploadDataBase = {}; // 存儲外部狀態 return { add: function(id, uploadType, fileName, fileSize){ var flyWeightObj = UploadFactory.create(uploadType); var dom = document.createElement("div"); dom.innerHTML = "..."; document.body.appendChild(dom); uploadDataBase[id] = { // 添加外部狀態 fileName: fileName, fileSize: fileSize, dom: dom }; return flyWeightObj; }, setExternalState: function(id, flyWeightObj){ // 設置外部狀態 var uploadData = uploadDataBase[id]; for(var i in uploadData){ flyWeightObj[i] = uploadData[i]; } } } })(); var id = 0; window.startUpload = function(uploadType, files){ for(var i = 0, file; file = files[i++];){ var uploadObj = uploadManager.add(++id, uploadType, file.fileName, file.fileSize); } }; startUpload("plugin", [ { fileName: "1.txt", fileSize: 1000 }, ... ]);對象池
對象池維護一個裝載空閑對象的池子,如果需要對象的時候,不是直接new,而是轉從對象池里獲取。如果對象池沒有空閑對象,則創建一個新的對象,當獲取出的對象完成它的職責之后,再進入池子等待被下次獲取。
var objectPoolFactory = function(createObjFn){ var objectPool = []; return { create: function(){ var obj = objectPool.length === 0 ? createObjFn.apply(this, arguments) : objectPool.shift(); return obj; }, recover: function(obj){ objectPool.push(obj); } }; }; // 現在利用`ObjectPoolFactory`來創建一個裝載一些`iframe`的對象池 var iframeFactory = objectPoolFactory(function(){ var iframe = document.createElement("iframe"); document.body.appendChild(iframe); iframe.onload = function(){ iframe.onload = null; iframeFactory.recover(iframe); } return iframe; }); var iframe1 = iframeFactory.create(); iframe1.src = "http://baidu.com"; var iframe2 = iframeFactory.create(); iframe2.src = "http://qq.com"; setTimeout(function(){ var iframe3 = iframeFactory.create(); iframe3.src = "http://163.com"; }, 3000);中介者模式
用一個中介者對象來封裝一系列的對象交互。中介者使各個對象之間不會相互引用。從而使其達到松散耦合的目的。
與觀察者模式對比來看,中介者模式是觀察者模式中的共享被觀察者對象。在這個系統中的對象之間直接的發布/訂閱關系被犧牲掉了,取而代之的是維護一個通信的中心節點。
寫程序是為了快速完成項目交付生產,而不是堆砌模式和過渡設計。關鍵就在于如何去衡量對象之間的耦合程度。如果對象之間的復雜耦合確實導致調用和維護出現了困難,而且這些耦合度隨項目的變化呈指數增長曲線,那就可以考慮用中介者模式來重構代碼。
function Player(name, teamColor){ this.name = name; // 角色名字 this.teamColor = teamColor; // 隊伍顏色 this.state = "alive"; // 玩家生存狀態 } Player.prototype.win = function(){ console.log("winner:" + this.name); }; Player.prototype.lose = function(){ console.log("loser:" + this.name); }; Player.prototype.die = function(){ this.state = "dead"; playerDirector.ReceiveMessage("playerDead", this); // 給中介者發送消息,玩家死亡 }; Player.prototype.remove = function(){ playerDirector.ReceiveMessage("removePlayer", this); // 給中介者發送消息,移除一個玩家 }; Player.prototype.changeTeam = function(){ playerDirector.ReceiveMessage("changeTeam", this); // 給中介者發送消息,玩家換隊 }; var playerFactory = function(name, teamColor){ var newPlayer = new Player(name, teamColor); playerDirector.ReceiveMessage("addPlayer", newPlayer); // 給中介者發送消息,新增玩家 return newPlayer; }; // 實現playerDirector對象 var playDirector = (function(){ var players = {}; // 保存所有玩家 var operations = {}; // 中介者可以執行的操作 // 新增一個玩家 operations.add = function(player){ var teamColor = player.teamColor; players[teamColor] = players[teamColor] || []; players[teamColor].push(player); }; // 移除一個玩家 operations.removePlayer = function(player){ var teamColor = player.teamColor; var teamPlayers = players[teamColor] || []; for(var i=teamPlayers.length - 1; i >= 0 ;i --){ if(teamPlayers[i] === player){ teamPlayers.splice(i, 1); } } }; // 玩家換隊 operations.changeTeam = function(player, newTeamColor){ operations.removePlayer(player); // 從原隊伍中刪除 player.teamColor = newTeamColor; // 換顏色 operations.addPlayer(player); // 新增玩家到新的隊伍 } operations.playerDead = function(player){ var teamColor = player.teamColor; var teamPlayer = players[teamColor]; var all_dead = true; // 遍歷隊友列表 for(var i=0, player; player = teamPlayer[i++];){ if(player.state !== "dead"){ all_dead = false; break; } } // 如果隊友全部死亡 if(all_dead === true){ this.lose(); // 通知所有隊友玩家游戲失敗 for(var i=0, player; player = teamPlayer[i++];){ player.lose(); } // 通知所有敵人游戲勝利 for(var color in players){ if(color !== teamColor){ var teamPlayers = players[color]; for(var i=0, player; player = teamPlayers[i++];){ player.win(); } } } } } var ReceiveMessage = function(){ var message = Array.prototype.shift.call(arguments); operations[message].apply(this, arguments); }; return { ReciveMessage: ReceiveMessage } })(); // 創建8個玩家對象 var player1 = playerFactory("a", "red"); var player2 = playerFactory("b", "red"); var player3 = playerFactory("c", "red"); var player4 = playerFactory("d", "red"); var player5 = playerFactory("e", "blue"); var player6 = playerFactory("f", "blue"); var player7 = playerFactory("g", "blue"); var player8 = playerFactory("h", "blue");裝飾者模式
給對象動態地增加職責的方式稱為裝飾者模式。
裝飾者模式能夠在不改變對象自身的基礎上,在程序運行期間給對象動態地添加職責。跟繼承相比,裝飾者是一種更輕便靈活的做法,這是一種“即用即付”的方式。
函數通過Function.prototype.before或者Function.prototype.after被裝飾之后,返回的實際上是一個新的函數,如果在原函數上保存了一些屬性,那么這些屬性會丟失。
這種裝飾方式也疊加了函數的作用域,如果裝飾的鏈條過長,性能上也會受到一些影響。
Function.prototype.before = function(beforeFn){ var _self = this; return function(){ if(beforefn.apply(this, arguments) === false){ return; }; return _self.apply(this, arguments); } }; var validata = function(){ if(username.value === ""){ alert("不能為空"); return false; } if(password.value === ""){ alert("不能為空"); return false; } }; var formSubmit = function(){ var param = { username: username.value, password: password.value }; ajax("...."); }; formSubmit = formSubimt.before(validata); submitBtn.onclick = function(){ formSubmit(); };狀態模式
狀態模式的關鍵是把事物的每種狀態都封裝成多帶帶的類,跟此種狀態有關的行為都被封裝在這個類的內部,只需要在上下文中,把某個請求委托給當前的狀態對象即可,該狀態對象會福州渲染它自身的行為。
// Light 類 var Light = function(){ this.offLightState = new OffLightState(this); this.weekLightState = new WeekLightState(this); this.strongLightState = new StrongLightState(this); this.button = null; }; Light.prototype.init = function(){ var button = document.createElement("button"); var self = this; this.button = document.body.appendChild(button); this.button.innerHTML = "開關"; this.currState = this.offLightState; this.button.onclick = function(){ self.currState.buttonWasPressed(); }; }; // offLightState var OffLightState = function(light){ this.light = light; }; OffLightState.prototype.buttonWasPressed = function(){ console.log("弱光") // offLightState 對應的行為 this.light.setState(this.light.weekLightState); // 切換狀態到 weekLightState };
文中代碼主要來自曾探老師的《JavaScript設計模式與開發實踐》,書中的內容關于設計模式寫的更加詳實細致,如果想學習設計模式推薦這本書入門哈!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99772.html
摘要:是你需要渲染到頁面的匹配規則的組件舉例最后一個將會渲染到內。舉例回調函數接收兩個參數是一個包含了所有匹配組件的一個組件,它用來渲染你的組件。調用或者是返回將會阻止阻止事件發射。 React/Router 文檔已廢棄,關閉更新,詳情請往 這里: React Router 一個針對React而設計的路由解決方案、可以友好的幫你解決React components 到URl之間的同步映射...
摘要:面試時經常會問到關于單例設計模式,因為它能考察的知識點較多且在開發中經常用到。那我就來說一說我對于單例設計模式的一些淺見。還有另一種實現方法稱為懶漢式。但以上代碼會出現線程安全問題。 Java面試時經常會問到關于單例設計模式,因為它能考察的知識點較多且在開發中經常用到。那我就來說一說我對于單例設計模式的一些淺見。首先,在Java中,什么是單例呢?就是保證類在內存中只有一個對象。那么問題...
摘要:前端面試每日題,以面試題來驅動學習,每天進步一點讓努力成為一種習慣,讓奮斗成為一種享受相信堅持的力量學習不打烊,充電加油只為遇到更好的自己,天無節假日,每天早上點純手工發布面試題死磕自己,愉悅大家。 《論語》,曾子曰:吾日三省吾身(我每天多次反省自己)。 前端面試每日3+1題,以面試題來驅動學習,每天進步一點! 讓努力成為一種習慣,讓奮斗成為一種享受!相信 堅持 的力量!??! ...
摘要:前端面試每日題,以面試題來驅動學習,每天進步一點讓努力成為一種習慣,讓奮斗成為一種享受相信堅持的力量學習不打烊,充電加油只為遇到更好的自己,天無節假日,每天早上點純手工發布面試題死磕自己,愉悅大家。 《論語》,曾子曰:吾日三省吾身(我每天多次反省自己)。 前端面試每日3+1題,以面試題來驅動學習,每天進步一點! 讓努力成為一種習慣,讓奮斗成為一種享受!相信 堅持 的力量?。。? ...
摘要:前端面試每日題,以面試題來驅動學習,每天進步一點讓努力成為一種習慣,讓奮斗成為一種享受相信堅持的力量項目地址推薦歡迎跟一起折騰前端,系統整理前端知識,目前正在折騰,打算打通算法與數據結構的任督二脈。 《論語》,曾子曰:吾日三省吾身(我每天多次反省自己)。 前端面試每日3+1題,以面試題來驅動學習,每天進步一點! 讓努力成為一種習慣,讓奮斗成為一種享受!相信 堅持 的力量?。?! 項目...
摘要:前端面試每日題,以面試題來驅動學習,每天進步一點讓努力成為一種習慣,讓奮斗成為一種享受相信堅持的力量項目地址推薦歡迎跟一起折騰前端,系統整理前端知識,目前正在折騰,打算打通算法與數據結構的任督二脈。 《論語》,曾子曰:吾日三省吾身(我每天多次反省自己)。 前端面試每日3+1題,以面試題來驅動學習,每天進步一點! 讓努力成為一種習慣,讓奮斗成為一種享受!相信 堅持 的力量?。?! 項目...
閱讀 1794·2023-04-26 02:14
閱讀 3719·2021-11-23 09:51
閱讀 1381·2021-10-13 09:39
閱讀 3963·2021-09-24 10:36
閱讀 3009·2021-09-22 15:55
閱讀 3511·2019-08-30 12:57
閱讀 2036·2019-08-29 15:30
閱讀 1980·2019-08-29 13:19