摘要:設計模式發布訂閱模式這種設計模式可以大大降低程序模塊之間的耦合度,便于更加靈活的擴展和維護。代理模式使得代理對象控制具體對象的引用。該模式使一個類的實例化延遲到了子類。
JS設計模式
這種設計模式可以大大降低程序模塊之間的耦合度,便于更加靈活的擴展和維護。
// 一個播放器類 class Player { constructor() { // 初始化觀察者列表 this.watchers = {} // 模擬2秒后發布一個"play"事件 setTimeout(() => { this._publish("play", true) }, 2000) // 模擬4秒后發布一個"pause"事件 setTimeout(() => { this._publish("pause", true) }, 4000) } // 發布事件 _publish(event, data) { if (this.watchers[event] && this.watchers[event].length) { this.watchers[event].forEach(callback => callback.bind(this)(data)) } } // 訂閱事件 subscribe(event, callback) { this.watchers[event] = this.watchers[event] || [] this.watchers[event].push(callback) } // 退訂事件 unsubscribe(event = null, callback = null) { // 如果傳入指定事件函數,則僅退訂此事件函數 if (callback&&event) { if (this.watchers[event] && this.watchers[event].length) { this.watchers[event].splice(this.watchers[event].findIndex(cb => Object.is(cb, callback)), 1) } // 如果僅傳入事件名稱,則退訂此事件對應的所有的事件函數 } else if (event) { this.watchers[event] = [] // 如果未傳入任何參數,則退訂所有事件 } else { this.watchers = {} } } } // 實例化播放器 const player = new Player() console.log(player) // 播放事件回調函數1 const onPlayerPlay1 = function(data) { console.log("1: Player is play, the `this` context is current player", this, data) } // 播放事件回調函數2 const onPlayerPlay2 = data => { console.log("2: Player is play", data) } // 暫停事件回調函數 const onPlayerPause = data => { console.log("Player is pause", data) } // 加載事件回調函數 const onPlayerLoaded = data => { console.log("Player is loaded", data) } // 可訂閱多個不同事件 player.subscribe("play", onPlayerPlay1) player.subscribe("play", onPlayerPlay2) player.subscribe("pause", onPlayerPause) player.subscribe("loaded", onPlayerLoaded) // 可以退訂指定訂閱事件 player.unsubscribe("play", onPlayerPlay2) // 退訂指定事件名稱下的所有訂閱事件 player.unsubscribe("play") // 退訂所有訂閱事件 player.unsubscribe() // 可以在外部手動發出事件(真實生產場景中,發布特性一般為類內部私有方法) player._publish("loaded", true)中介者模式 Mediator Pattern:
觀察者模式通過維護一堆列表來管理對象間的多對多關系,中介者模式通過統一接口來維護一對多關系,且通信者之間不需要知道彼此之間的關系,只需要約定好API即可。
// 汽車 class Bus { constructor() { // 初始化所有乘客 this.passengers = {} } // 發布廣播 broadcast(passenger, message = passenger) { // 如果車上有乘客 if (Object.keys(this.passengers).length) { // 如果是針對某個乘客發的,就多帶帶給他聽 if (passenger.id && passenger.listen) { // 乘客他愛聽不聽 if (this.passengers[passenger.id]) { this.passengers[passenger.id].listen(message) } // 不然就廣播給所有乘客 } else { Object.keys(this.passengers).forEach(passenger => { if (this.passengers[passenger].listen) { this.passengers[passenger].listen(message) } }) } } } // 乘客上車 aboard(passenger) { this.passengers[passenger.id] = passenger } // 乘客下車 debus(passenger) { this.passengers[passenger.id] = null delete this.passengers[passenger.id] console.log(`乘客${passenger.id}下車`) } // 開車 start() { this.broadcast({ type: 1, content: "前方無障礙,開車!Over"}) } // 停車 end() { this.broadcast({ type: 2, content: "老司機翻車,停車!Over"}) } } // 乘客 class Passenger { constructor(id) { this.id = id } // 聽廣播 listen(message) { console.log(`乘客${this.id}收到消息`, message) // 乘客發現停車了,于是自己下車 if (Object.is(message.type, 2)) { this.debus() } } // 下車 debus() { console.log(`我是乘客${this.id},我現在要下車`, bus) bus.debus(this) } } // 創建一輛汽車 const bus = new Bus() // 創建兩個乘客 const passenger1 = new Passenger(1) const passenger2 = new Passenger(2) // 倆乘客分別上車 bus.aboard(passenger1) bus.aboard(passenger2) // 2秒后開車 setTimeout(bus.start.bind(bus), 2000) // 3秒時司機發現2號乘客沒買票,2號乘客被驅逐下車 setTimeout(() => { bus.broadcast(passenger2, { type: 3, content: "同志你好,你沒買票,請下車!" }) bus.debus(passenger2) }, 3000) // 4秒后到站停車 setTimeout(bus.end.bind(bus), 3600) // 6秒后再開車,車上已經沒乘客了 setTimeout(bus.start.bind(bus), 6666)代理模式 Proxy Pattern:
為其他對象提供一種代理以控制對這個對象的訪問。
代理模式使得代理對象控制具體對象的引用。代理幾乎可以是任何對象:文件,資源,內存中的對象,或者是一些難以復制的東西。
ES6中的Proxy對象
const target = {} const handler = { get(target, property) { if (property in target) { return target[property] } else { throw new ReferenceError("Property "" + property + "" does not exist.") } } } const p = new Proxy(target, {}) p.a = 3 // 被轉發到代理的操作 console.log(p.c) //單例模式 Singleton Pattern:
保證一個類只有一個實例,并提供一個訪問它的全局訪問點(調用一個類,任何時候返回的都是同一個實例)。
實現方法:使用一個變量來標志當前是否已經為某個類創建過對象,如果創建了,則在下一次獲取該類的實例時,直接返回之前創建的對象,否則就創建一個對象。
// 類數實例: class Singleton { constructor(name) { this.name = name this.instance = null // } getName() { alert(this.name) } static getInstance(name) { if (!this.instance) { this.instance = new Singleton(name) } return this.instance } } const ins = new Singleton("hhhh") const instanceA = Singleton.getInstance("seven1") const instanceB = Singleton.getInstance("seven2") //閉包包裝實例: const SingletonP = (function() { let instance return class Singleton { constructor(name) { if (instance) { return instance } else { this.init(name) instance = this return this } } init(name) { this.name = name console.log("已初始化") } } })() const instanceA = new SingletonP("seven1") const instanceB = new SingletonP("seven2") // ES5 iife var SingletonTester = (function () { function Singleton(args) { var args = args || {}; //設置name參數 this.name = "SingletonTester"; } //實例容器 var instance; return { name: "SingletonTester", getInstance: function (args) { if (instance === undefined) { instance = new Singleton(args); } return instance; } }; })(); var singletonTest = SingletonTester.getInstance({ pointX: 5 }); console.log(singletonTest.pointX); // 輸出 5 // 構造函數的屬性 function Universe() { if (typeof Universe.instance === "object") { return Universe.instance; } this.start_time = 0; this.bang = "Big"; Universe.instance = this; } // 測試 var uni = new Universe(); var uni2 = new Universe(); console.log(uni === uni2); // true // 重寫構造函數 function Universe() { var instance = this; // 其它內容 this.start_time = 0; this.bang = "Big"; // 重寫構造函數 Universe = function () { return instance; }; } // 測試 var uni = new Universe(); var uni2 = new Universe(); uni.bang = "123"; console.log(uni === uni2); // true console.log(uni2.bang); // 123工廠模式 Factory Pattern:
工廠模式定義一個用于創建對象的接口,這個接口由子類決定實例化哪一個類。該模式使一個類的實例化延遲到了子類。而子類可以重寫接口方法以便創建的時候指定自己的對象類型。
簡單說:假如我們想在網頁面里插入一些元素,而這些元素類型不固定,可能是圖片、鏈接、文本,根據工廠模式的定義,在工廠模式下,工廠函數只需接受我們要創建的元素的類型,其他的工廠函數幫我們處理。
// 文本工廠 class Text { constructor(text) { this.text = text } insert(where) { const txt = document.createTextNode(this.text) where.appendChild(txt) } } // 鏈接工廠 class Link { constructor(url) { this.url = url } insert(where) { const link = document.createElement("a") link.href = this.url link.appendChild(document.createTextNode(this.url)) where.appendChild(link) } } // 圖片工廠 class Image { constructor(url) { this.url = url } insert(where) { const img = document.createElement("img") img.src = this.url where.appendChild(img) } } // DOM工廠 class DomFactory { constructor(type) { return new (this[type]()) } // 各流水線 link() { return Link } text() { return Text } image() { return Image } } // 創建工廠 const linkFactory = new DomFactory("link") const textFactory = new DomFactory("text") linkFactory.url = "https://surmon.me" linkFactory.insert(document.body) textFactory.text = "HI! I am surmon." textFactory.insert(document.body)裝飾者模式 Decorative Pattern:
裝飾者(decorator)模式能夠在不改變對象自身的基礎上,在程序運行期間給對像動態的添加職責(方法或屬性)。與繼承相比,裝飾者是一種更輕便靈活的做法。
簡單說:可以動態的給某個對象添加額外的職責,而不會影響從這個類中派生的其它對象。
ES7裝飾器 function isAnimal(target) { target.isAnimal = true return target } // 裝飾器 @isAnimal class Cat { // ... } console.log(Cat.isAnimal) // true 作用于類屬性的裝飾器: function readonly(target, name, descriptor) { discriptor.writable = false return discriptor } class Cat { @readonly say() { console.log("meow ~") } } var kitty = new Cat() kitty.say = function() { console.log("woof !") } kitty.say() // meow ~
參考:
輸入理解js系列
來自ES6入門實踐
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/51200.html
摘要:道阻且長啊前端面試總結前端面試筆試面試騰訊一面瀏覽器工作原理瀏覽器的主要組件包括用戶界面包括地址欄后退前進按鈕書簽目錄瀏覽器引擎用來查詢及操作渲染引擎的接口渲染引擎渲染界面和是基于兩種渲染引擎構建的,使用自主研發的渲染引擎,和都使用網絡用來 道阻且長啊TAT(前端面試總結) 前端 面試 筆試 面試 騰訊一面 1.瀏覽器工作原理 瀏覽器的主要組件包括: 用戶界面- 包括地址欄、后退/前...
摘要:道阻且長啊前端面試總結前端面試筆試面試騰訊一面瀏覽器工作原理瀏覽器的主要組件包括用戶界面包括地址欄后退前進按鈕書簽目錄瀏覽器引擎用來查詢及操作渲染引擎的接口渲染引擎渲染界面和是基于兩種渲染引擎構建的,使用自主研發的渲染引擎,和都使用網絡用來 道阻且長啊TAT(前端面試總結) 前端 面試 筆試 面試 騰訊一面 1.瀏覽器工作原理 瀏覽器的主要組件包括: 用戶界面- 包括地址欄、后退/前...
摘要:道阻且長啊前端面試總結前端面試筆試面試騰訊一面瀏覽器工作原理瀏覽器的主要組件包括用戶界面包括地址欄后退前進按鈕書簽目錄瀏覽器引擎用來查詢及操作渲染引擎的接口渲染引擎渲染界面和是基于兩種渲染引擎構建的,使用自主研發的渲染引擎,和都使用網絡用來 道阻且長啊TAT(前端面試總結) 前端 面試 筆試 面試 騰訊一面 1.瀏覽器工作原理 瀏覽器的主要組件包括: 用戶界面- 包括地址欄、后退/前...
摘要:之面向對象對象類型數據類型分六類簡單類型五種復雜類型其中也屬于基本類型。 js之面向對象(OOP) js對象類型(Object) js數據類型分六類,簡單類型:Undefined,Null,Bollean,Number,String五種,復雜類型:Object.其中Undefined、Null、Boolean、Number也屬于基本類型。Object、Array和Function則屬...
摘要:獨立構建和運行時構建的區別標簽空格分隔未分類在使用時,有獨立構建和運行時構建兩種版本可供選擇。運行時構建不包括模板編譯,不支持選項。這就形成了獨立構建編譯器運行時和運行時構建僅運行時。 Vue.js 2.0 獨立構建和運行時構建的區別 標簽(空格分隔): 未分類 在使用 Vue.js 2.0 時,有獨立構建(standalone)和運行時構建(runtime-only)兩種版本可供選...
閱讀 5201·2021-10-15 09:42
閱讀 1606·2021-09-22 16:05
閱讀 3262·2021-09-22 15:57
閱讀 3396·2019-12-27 12:06
閱讀 967·2019-08-29 15:16
閱讀 2880·2019-08-26 12:24
閱讀 380·2019-08-26 12:02
閱讀 1885·2019-08-23 16:00