摘要:設(shè)計(jì)模式發(fā)布訂閱模式這種設(shè)計(jì)模式可以大大降低程序模塊之間的耦合度,便于更加靈活的擴(kuò)展和維護(hù)。代理模式使得代理對象控制具體對象的引用。該模式使一個(gè)類的實(shí)例化延遲到了子類。
JS設(shè)計(jì)模式
這種設(shè)計(jì)模式可以大大降低程序模塊之間的耦合度,便于更加靈活的擴(kuò)展和維護(hù)。
// 一個(gè)播放器類 class Player { constructor() { // 初始化觀察者列表 this.watchers = {} // 模擬2秒后發(fā)布一個(gè)"play"事件 setTimeout(() => { this._publish("play", true) }, 2000) // 模擬4秒后發(fā)布一個(gè)"pause"事件 setTimeout(() => { this._publish("pause", true) }, 4000) } // 發(fā)布事件 _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) { // 如果傳入指定事件函數(shù),則僅退訂此事件函數(shù) 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) } // 如果僅傳入事件名稱,則退訂此事件對應(yīng)的所有的事件函數(shù) } else if (event) { this.watchers[event] = [] // 如果未傳入任何參數(shù),則退訂所有事件 } else { this.watchers = {} } } } // 實(shí)例化播放器 const player = new Player() console.log(player) // 播放事件回調(diào)函數(shù)1 const onPlayerPlay1 = function(data) { console.log("1: Player is play, the `this` context is current player", this, data) } // 播放事件回調(diào)函數(shù)2 const onPlayerPlay2 = data => { console.log("2: Player is play", data) } // 暫停事件回調(diào)函數(shù) const onPlayerPause = data => { console.log("Player is pause", data) } // 加載事件回調(diào)函數(shù) const onPlayerLoaded = data => { console.log("Player is loaded", data) } // 可訂閱多個(gè)不同事件 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() // 可以在外部手動發(fā)出事件(真實(shí)生產(chǎn)場景中,發(fā)布特性一般為類內(nèi)部私有方法) player._publish("loaded", true)中介者模式 Mediator Pattern:
觀察者模式通過維護(hù)一堆列表來管理對象間的多對多關(guān)系,中介者模式通過統(tǒng)一接口來維護(hù)一對多關(guān)系,且通信者之間不需要知道彼此之間的關(guān)系,只需要約定好API即可。
// 汽車 class Bus { constructor() { // 初始化所有乘客 this.passengers = {} } // 發(fā)布廣播 broadcast(passenger, message = passenger) { // 如果車上有乘客 if (Object.keys(this.passengers).length) { // 如果是針對某個(gè)乘客發(fā)的,就多帶帶給他聽 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: "老司機(jī)翻車,停車!Over"}) } } // 乘客 class Passenger { constructor(id) { this.id = id } // 聽廣播 listen(message) { console.log(`乘客${this.id}收到消息`, message) // 乘客發(fā)現(xiàn)停車了,于是自己下車 if (Object.is(message.type, 2)) { this.debus() } } // 下車 debus() { console.log(`我是乘客${this.id},我現(xiàn)在要下車`, bus) bus.debus(this) } } // 創(chuàng)建一輛汽車 const bus = new Bus() // 創(chuàng)建兩個(gè)乘客 const passenger1 = new Passenger(1) const passenger2 = new Passenger(2) // 倆乘客分別上車 bus.aboard(passenger1) bus.aboard(passenger2) // 2秒后開車 setTimeout(bus.start.bind(bus), 2000) // 3秒時(shí)司機(jī)發(fā)現(xiàn)2號乘客沒買票,2號乘客被驅(qū)逐下車 setTimeout(() => { bus.broadcast(passenger2, { type: 3, content: "同志你好,你沒買票,請下車!" }) bus.debus(passenger2) }, 3000) // 4秒后到站停車 setTimeout(bus.end.bind(bus), 3600) // 6秒后再開車,車上已經(jīng)沒乘客了 setTimeout(bus.start.bind(bus), 6666)代理模式 Proxy Pattern:
為其他對象提供一種代理以控制對這個(gè)對象的訪問。
代理模式使得代理對象控制具體對象的引用。代理幾乎可以是任何對象:文件,資源,內(nèi)存中的對象,或者是一些難以復(fù)制的東西。
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 // 被轉(zhuǎn)發(fā)到代理的操作 console.log(p.c) //單例模式 Singleton Pattern:
保證一個(gè)類只有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)(調(diào)用一個(gè)類,任何時(shí)候返回的都是同一個(gè)實(shí)例)。
實(shí)現(xiàn)方法:使用一個(gè)變量來標(biāo)志當(dāng)前是否已經(jīng)為某個(gè)類創(chuàng)建過對象,如果創(chuàng)建了,則在下一次獲取該類的實(shí)例時(shí),直接返回之前創(chuàng)建的對象,否則就創(chuàng)建一個(gè)對象。
// 類數(shù)實(shí)例: 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") //閉包包裝實(shí)例: 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 || {}; //設(shè)置name參數(shù) this.name = "SingletonTester"; } //實(shí)例容器 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 // 構(gòu)造函數(shù)的屬性 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 // 重寫構(gòu)造函數(shù) function Universe() { var instance = this; // 其它內(nèi)容 this.start_time = 0; this.bang = "Big"; // 重寫構(gòu)造函數(shù) 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:
工廠模式定義一個(gè)用于創(chuàng)建對象的接口,這個(gè)接口由子類決定實(shí)例化哪一個(gè)類。該模式使一個(gè)類的實(shí)例化延遲到了子類。而子類可以重寫接口方法以便創(chuàng)建的時(shí)候指定自己的對象類型。
簡單說:假如我們想在網(wǎng)頁面里插入一些元素,而這些元素類型不固定,可能是圖片、鏈接、文本,根據(jù)工廠模式的定義,在工廠模式下,工廠函數(shù)只需接受我們要創(chuàng)建的元素的類型,其他的工廠函數(shù)幫我們處理。
// 文本工廠 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 } } // 創(chuàng)建工廠 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)模式能夠在不改變對象自身的基礎(chǔ)上,在程序運(yùn)行期間給對像動態(tài)的添加職責(zé)(方法或?qū)傩裕?。與繼承相比,裝飾者是一種更輕便靈活的做法。
簡單說:可以動態(tài)的給某個(gè)對象添加額外的職責(zé),而不會影響從這個(gè)類中派生的其它對象。
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入門實(shí)踐
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/51200.html
摘要:道阻且長啊前端面試總結(jié)前端面試筆試面試騰訊一面瀏覽器工作原理瀏覽器的主要組件包括用戶界面包括地址欄后退前進(jìn)按鈕書簽?zāi)夸洖g覽器引擎用來查詢及操作渲染引擎的接口渲染引擎渲染界面和是基于兩種渲染引擎構(gòu)建的,使用自主研發(fā)的渲染引擎,和都使用網(wǎng)絡(luò)用來 道阻且長啊TAT(前端面試總結(jié)) 前端 面試 筆試 面試 騰訊一面 1.瀏覽器工作原理 瀏覽器的主要組件包括: 用戶界面- 包括地址欄、后退/前...
摘要:道阻且長啊前端面試總結(jié)前端面試筆試面試騰訊一面瀏覽器工作原理瀏覽器的主要組件包括用戶界面包括地址欄后退前進(jìn)按鈕書簽?zāi)夸洖g覽器引擎用來查詢及操作渲染引擎的接口渲染引擎渲染界面和是基于兩種渲染引擎構(gòu)建的,使用自主研發(fā)的渲染引擎,和都使用網(wǎng)絡(luò)用來 道阻且長啊TAT(前端面試總結(jié)) 前端 面試 筆試 面試 騰訊一面 1.瀏覽器工作原理 瀏覽器的主要組件包括: 用戶界面- 包括地址欄、后退/前...
摘要:道阻且長啊前端面試總結(jié)前端面試筆試面試騰訊一面瀏覽器工作原理瀏覽器的主要組件包括用戶界面包括地址欄后退前進(jìn)按鈕書簽?zāi)夸洖g覽器引擎用來查詢及操作渲染引擎的接口渲染引擎渲染界面和是基于兩種渲染引擎構(gòu)建的,使用自主研發(fā)的渲染引擎,和都使用網(wǎng)絡(luò)用來 道阻且長啊TAT(前端面試總結(jié)) 前端 面試 筆試 面試 騰訊一面 1.瀏覽器工作原理 瀏覽器的主要組件包括: 用戶界面- 包括地址欄、后退/前...
摘要:之面向?qū)ο髮ο箢愋蛿?shù)據(jù)類型分六類簡單類型五種復(fù)雜類型其中也屬于基本類型。 js之面向?qū)ο?OOP) js對象類型(Object) js數(shù)據(jù)類型分六類,簡單類型:Undefined,Null,Bollean,Number,String五種,復(fù)雜類型:Object.其中Undefined、Null、Boolean、Number也屬于基本類型。Object、Array和Function則屬...
摘要:獨(dú)立構(gòu)建和運(yùn)行時(shí)構(gòu)建的區(qū)別標(biāo)簽空格分隔未分類在使用時(shí),有獨(dú)立構(gòu)建和運(yùn)行時(shí)構(gòu)建兩種版本可供選擇。運(yùn)行時(shí)構(gòu)建不包括模板編譯,不支持選項(xiàng)。這就形成了獨(dú)立構(gòu)建編譯器運(yùn)行時(shí)和運(yùn)行時(shí)構(gòu)建僅運(yùn)行時(shí)。 Vue.js 2.0 獨(dú)立構(gòu)建和運(yùn)行時(shí)構(gòu)建的區(qū)別 標(biāo)簽(空格分隔): 未分類 在使用 Vue.js 2.0 時(shí),有獨(dú)立構(gòu)建(standalone)和運(yùn)行時(shí)構(gòu)建(runtime-only)兩種版本可供選...
閱讀 5258·2021-10-15 09:42
閱讀 1621·2021-09-22 16:05
閱讀 3281·2021-09-22 15:57
閱讀 3418·2019-12-27 12:06
閱讀 978·2019-08-29 15:16
閱讀 2888·2019-08-26 12:24
閱讀 391·2019-08-26 12:02
閱讀 1897·2019-08-23 16:00