學(xué)習(xí)JavaScript設(shè)計(jì)模式之裝飾者模式
有時(shí)我們不希望某個(gè)類天生就非常龐大,一次性包含許多職責(zé)。那么我們就可以使用裝飾著模式。
裝飾著模式可以動(dòng)態(tài)地給某個(gè)對(duì)象添加一些額外的職責(zé),從而不影響這個(gè)類中派生的其他對(duì)象。
裝飾著模式將一個(gè)對(duì)象嵌入另一個(gè)對(duì)象之中,實(shí)際上相當(dāng)于這個(gè)對(duì)象被另一個(gè)對(duì)象包裝起來(lái),形成一條包裝鏈。
一、不改動(dòng)原函數(shù)的情況下,給該函數(shù)添加些額外的功能
1. 保存原引用
window.onload = function() { console.log(1); }; var _onload = window.onload || function() {}; window.onload = function() { _onload(); console.log(2); }
問(wèn)題:
(1)必須維護(hù)中間變量
(2)可能遇到this被劫持問(wèn)題
在window.onload的例子中沒(méi)有這個(gè)煩惱,是因?yàn)檎{(diào)用普通函數(shù)_onload時(shí),this也指向window,跟調(diào)用window.onload時(shí)一樣。
2. this被劫持:
var _getElementById = document.getElementById; document.getElementById = function(id) { console.log(1); return _getElementById(id); } return _getElementById(id); // 報(bào)錯(cuò)“Uncaught TypeError: Illegal invocation”
因?yàn)開(kāi)getElementById是全局函數(shù),當(dāng)調(diào)用全局函數(shù)時(shí),this是指向window的,而document.getElementById中this預(yù)期指向document。
3. 解決this被劫持:
var _getElementById = document.getElementById; document.getElementById = function(id) { console.log(1); return _getElementById.call(document, id); }
二、用AOP裝飾函數(shù)
/* 讓新添加的函數(shù)在原函數(shù)之前執(zhí)行(前置裝飾)*/ Function.prototype.before = function(beforefn) { var _self = this; return function() { beforefn.apply(this, arguments); // 新函數(shù)接收的參數(shù)會(huì)被原封不動(dòng)的傳入原函數(shù) return _self.apply(this, arguments); }; };
/* 讓新添加的函數(shù)在原函數(shù)之后執(zhí)行(后置裝飾)*/ Function.prototype.after = function(afterfn) { var _self = this; return function() { var ret = _self.apply(this, arguments); afterfn.apply(this, arguments); return ret; }; };
document.getElementById = document.getElementById.before(function() { console.log(1); });
三、避免污染原型
var before = function(fn, beforefn) { return function() { beforefn.apply(this, arguments); return fn.apply(this, arguments); }; }; var after = function(fn, afterfn) { return function() { var ret = fn.apply(this, arguments); afterfn.apply(this, arguments); return ret; }; }; document.getElementById = before(document.getElementById, function(){ console.log(1); });
四、示例–插件式的表單驗(yàn)證
結(jié)合《學(xué)習(xí)JavaScript設(shè)計(jì)模式之策略模式》中的【表單驗(yàn)證】,運(yùn)用到ajax提交數(shù)據(jù)驗(yàn)證,效果很棒!
修改上述before方法
var before = function(fn, beforefn) { return function() { if(beforefn.apply(this, arguments) === false) { // beforefn返回false,直接return,不執(zhí)行后面的原函數(shù) return; } return fn.apply(this, arguments); }; };
/* 模擬數(shù)據(jù)驗(yàn)證*/ var validate = function() { if(username === "") { console.log("驗(yàn)證失??!"); return false; } return true; } /* 模擬ajax提交*/ var formSubmit = function() { console.log("提交?。?!"); }
username = 1; formSubmit = before(formSubmit, validate); // 提交?。?! formSubmit(); username = ""; formSubmit = before(formSubmit, validate); // 驗(yàn)證失??! formSubmit();
五、裝飾者模式和代理模式
相同點(diǎn):這兩種模式都描述了怎么為對(duì)象提供一定程度上的間接引用,它們的實(shí)現(xiàn)部分都保留了對(duì)另外一個(gè)對(duì)象的引用,并且向那個(gè)對(duì)象發(fā)送請(qǐng)求。
區(qū)別:
(1)代理模式:當(dāng)直接訪問(wèn)本地不方便或者不符合需求時(shí),為這個(gè)本體提供一個(gè)替代者。本地定義關(guān)鍵功能,而代理提供或拒絕對(duì)它的訪問(wèn),或者在訪問(wèn)本體之前走一些額外的事情。(其做的事情還是跟本體一樣)
(2)裝飾者模式:為對(duì)象動(dòng)態(tài)加入行為。(一開(kāi)始不能確定對(duì)象的全部功能,實(shí)實(shí)在在的為對(duì)象添加新的職責(zé)和行為)
希望本文所述對(duì)大家學(xué)習(xí)javascript程序設(shè)計(jì)有所幫助。
相關(guān)文章
JavaScript筆記之?dāng)?shù)據(jù)屬性和存儲(chǔ)器屬性
本文給大家介紹js數(shù)據(jù)屬性和存儲(chǔ)器屬性,及兩種屬性的區(qū)別,對(duì)js數(shù)據(jù)屬性存儲(chǔ)器屬性相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)2016-03-03CSS3 動(dòng)畫卡頓性能優(yōu)化的完美解決方案
今天小編就為大家分享一篇關(guān)于css3 動(dòng)畫卡頓性能優(yōu)化的完美解決方案,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-09-09學(xué)習(xí)JavaScript事件流和事件處理程序
這篇文章主要為大家介紹了學(xué)習(xí)JavaScript事件流和事件處理程序的注意事項(xiàng),感興趣的小伙伴們可以參考一下2016-01-01JavaScript 異步調(diào)用框架 (Part 3 - 代碼實(shí)現(xiàn))
在上一篇文章里,我們說(shuō)到了要實(shí)現(xiàn)一個(gè)Async.Operation類,通過(guò)addCallback方法傳遞回調(diào)函數(shù),并且通過(guò)yield方法返回回調(diào)結(jié)果?,F(xiàn)在我們就來(lái)實(shí)現(xiàn)這個(gè)類吧。2009-08-08微信小程序?qū)崿F(xiàn)單選選項(xiàng)卡切換效果
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)單選選項(xiàng)卡切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02js模仿windows桌面圖標(biāo)排列算法具體實(shí)現(xiàn)(附圖)
需要引入Jquery,如果需要全部功能,請(qǐng)引入jquery-ui和jquery-ui.css,具體實(shí)現(xiàn)步驟如下,感興趣的朋友可以參考下哈2013-06-06