javascript
JS代理模式《JavaScript设计模式与开发实践》阅读笔记
代理模式
代理模式是為一個(gè)對(duì)象提供一個(gè)代用品或占位符,以便控制對(duì)它的訪問(wèn)。
保護(hù)代理和虛擬代理
保護(hù)代理:當(dāng)有許多需求要向某對(duì)象發(fā)出一些請(qǐng)求時(shí),可以設(shè)置保護(hù)代理,通過(guò)一些條件判斷對(duì)請(qǐng)求進(jìn)行過(guò)濾。
虛擬代理:在程序中可以能有一些代價(jià)昂貴的操作。此時(shí)可以設(shè)置虛擬代理去代為執(zhí)行,這里的虛擬代理便會(huì)在適合的時(shí)候(需要用到的時(shí)候)才去執(zhí)行。
保護(hù)代理用于控制不同權(quán)限的對(duì)象對(duì)目標(biāo)對(duì)象的訪問(wèn),但在JavaScript并不容易實(shí)現(xiàn)保護(hù)代理,因?yàn)槲覀儫o(wú)法判斷誰(shuí)訪問(wèn)了某個(gè)對(duì)象。而虛擬代理是最常用的一種代理模式。虛擬代理實(shí)現(xiàn)圖片預(yù)加載
預(yù)加載圖片在Web開(kāi)發(fā)中十分常用,其通過(guò)異步的方式加載圖片,利用一張loading圖片占位。等圖片加載好之后把圖片填充到img節(jié)點(diǎn)中。
var myImage = (function(){var imgNode = document.createElement('img')document.body.appendChild(imgNode)return {setSrc: function(src){imgNode.src = src}} })()var proxyImage = (function(){var img = new Image()img.onload = function(){myImage.setSrc(this.src)}return {setSrc: function(src){ myImage.setSrc('loading.gif')img.src = src}} })()proxyImage.setSrc('realImage.jpg') 通過(guò)proxyImage間接的訪問(wèn)了MyImage。proxyImage控制了客戶對(duì)MyImage的訪問(wèn),并且在此過(guò)程中加入了一些額外的操作,比如在真正的圖片加載好之前,先把img節(jié)點(diǎn)的src設(shè)置為一張loading圖片。代理的意義
面向?qū)ο笤O(shè)計(jì)原則——單一職責(zé)原則。單一職責(zé)原則指的是,就一個(gè)類(通常也包括對(duì)象和函數(shù)等)而言,應(yīng)該僅有一個(gè)引起它變化的原因。如果一個(gè)對(duì)象承擔(dān)了多項(xiàng)職責(zé),就意味著這個(gè)對(duì)象將變得巨大,引起它變化的原因會(huì)有多個(gè)。面向?qū)ο笤O(shè)計(jì)鼓勵(lì)將行為分布到細(xì)粒度的對(duì)象之中,如果一個(gè)對(duì)象承擔(dān)的職責(zé)過(guò)多,等于把這些職責(zé)耦合到了一起,這種耦合會(huì)導(dǎo)致脆弱和低內(nèi)聚的設(shè)計(jì),帶變化發(fā)生時(shí),設(shè)計(jì)可能會(huì)遭到意外的破壞。虛擬代理例子中,代理模式給系統(tǒng)添加了額外的功能,預(yù)加載圖片。而我們實(shí)際需要的只是MyImage的setImage方法。預(yù)加載只是一個(gè)錦上添花的功能。通過(guò)代理模式使得這兩個(gè)功能獨(dú)立開(kāi)來(lái),遵循了開(kāi)放-封閉原則。
緩存代理
緩存代理可以為一些開(kāi)銷大的運(yùn)算結(jié)果提供暫時(shí)的存儲(chǔ),在下次運(yùn)算時(shí),如果傳遞進(jìn)來(lái)的參數(shù)跟之前一致,則可以直接返回前面存儲(chǔ)的運(yùn)算結(jié)果。乘積運(yùn)算的例子
/*******計(jì)算乘積******/ var mult = function(){console.log('開(kāi)始計(jì)算乘積')var a = 1 for (var i = 0,l = arguments.length;i<l;i++){a = a*arguments[i]}return a }/********乘積代理函數(shù)********/ var proxyMult = (function(){var cache = {} // 緩存對(duì)象return function(){var args = Array.prototype.join.call(arguments,',') // 將參數(shù)轉(zhuǎn)化成字符串作為cache的keyif (args in cache){// 如果cache對(duì)象中存儲(chǔ)了同樣的參數(shù),直接返回對(duì)應(yīng)的運(yùn)算結(jié)果console.log('緩存結(jié)果:')return cache[args]}// 如果沒(méi)有該運(yùn)算參數(shù),保存新的參數(shù)和結(jié)果,并調(diào)用mult方法返回運(yùn)算結(jié)果。return cache[args] = mult.apply(this, arguments)} })()console.clear() console.log(proxyMult(1,2,3,4,5)) // mult運(yùn)算 console.log(proxyMult(1,2,3,4,5)) // 讀取緩存結(jié)果 console.log(proxyMult(1,2,3,4)) // mult運(yùn)算 console.log(proxyMult(1,2,3,4)) // 讀取緩存結(jié)果/*******創(chuàng)建緩存代理的工廠函數(shù)*******/ var createProxyFactory = function(fn){var cache = {}return function(){var args = Array.prototype.join.call(arguments,',')if(args in cache){return cache[args]}return cache[args] = fn.apply(this, arguments)} } var proxyMult = createProxyFactory(mult) console.log(proxyMult(12,3,4,5,6)) console.log(proxyMult(12,3,4,5,6))最后
雖然代理模式非常有用,但我們?cè)诰帉?xiě)業(yè)務(wù)代碼的時(shí)候,往往不需要去預(yù)先猜測(cè)是否需要使用代理模式。當(dāng)真正發(fā)現(xiàn)不方便直接訪問(wèn)某個(gè)對(duì)象的時(shí)候,再編寫(xiě)代理不遲。代理模式是一種很實(shí)用的設(shè)計(jì)模式,很好的詮釋了面向?qū)ο笾械膯我宦氊?zé)原則和開(kāi)放-封閉原則。在實(shí)際開(kāi)發(fā)的時(shí)候往往會(huì)迫于進(jìn)度壓力或者實(shí)現(xiàn)了再說(shuō)的態(tài)度忽略了一些必要的代碼的可維護(hù)性,我覺(jué)得在一些簡(jiǎn)單的地方去試著遵循一些設(shè)計(jì)理念是對(duì)自己代碼能力的提升。當(dāng)然不要為了設(shè)計(jì)而設(shè)計(jì)啦。
Done is better then Perfect
參考
《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》—— 曾探
總結(jié)
以上是生活随笔為你收集整理的JS代理模式《JavaScript设计模式与开发实践》阅读笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 我的WAF Bypass实战系列
- 下一篇: Sense编辑器(Sense Edito