摘要:如果我們認為模式代表一個最佳的實踐,那么反模式將代表我們已經(jīng)學到一個教訓。受啟發(fā)于的設計模式,在年的月的報告大會上首次提出反模式。參考鏈接反模式學用設計模式極客學院
如果我們認為模式代表一個最佳的實踐,那么反模式將代表我們已經(jīng)學到一個教訓。受啟發(fā)于Gof的《設計模式》,Andrew Koeing在1995年的11月的C++報告大會上首次提出反模式。在Koeing的報告中,反模式有著兩種觀念:
描述對于一個特殊的問題,提出了一個糟糕的解決方案,最終導致一個壞結(jié)果發(fā)生
描述如何擺脫上述解決方案并能提出一個好的解決方案
在如今這個前端發(fā)展如火如荼的時代,談及jq總是顯得非常的low,但實際上,在學校,在很多前端新人以及所謂“頁面仔 || 切圖工”之類的同行之間,jq的活力還是遠超各種框架的時候,之所以想寫這樣一篇文章,一是因為見到了身邊的jq爛代碼,二是因為我在百度jQuery反模式的時候居然什么有價值的相關(guān)結(jié)果都沒有,所以覺得還是有必要聊聊的。
先從些簡單的開始: 插入DOM節(jié)點:// 反模式 $.each(reallyLongArray, function(count, item) { var newLi = "
DocumentFragment是瀏覽器為了減少DOM操作中的更新所使用的API,詳情請查閱MDN相關(guān)文檔。
遵循DRY原則:if ($a.data("current") != "showing") { $a.stop() } if ($b.data("current") != "showing") { $b.stop() } if ($c.data("current") != "showing") { $c.stop() } // 用數(shù)組來保存不同的主體 var elems = [$a, $b, $c] $.each(elems, function(k, v) { if (v.data("current") != "showing") { v.stop() } })
用數(shù)組或?qū)ο髞肀4嬷貜推蔚牟町悈?shù)是一種很常見的方法。更多內(nèi)容可以參考常見的JavaScript設計模式中的“九、策略模式”
地獄式回調(diào)(callback hell):$(document).ready(function() { $("#button").click(function() { $.get("http://api.github.com/repos/facebook/react/forks", function(data) { alert(data[0].owner.login) }) }) }) // 以前有這么一種優(yōu)化的方法,使用對象字面量保存回調(diào)使其扁平化 var cbContainer = { initApp: function() { $(document).ready(cbContainer.readCb) }, readyCb: function() { $("#button").click(cbContainer.clickCb) }, clickCb: function() { $.get("http://api.github.com/repos/facebook/react/forks", function(data) { cbContainer.getCb(data) }) }, getCb: function(data) { alert(data[0].owner.login) } } cbContainer.initApp() // 不過現(xiàn)在流行Promise var initApp = function() { return new Promise(function(resolve, reject) { $(document).ready(resolve) }) } var readyCb = function() { return new Promise(function(resolve, reject) { $("#button").click(resolve) }) } var clickCb = function() { return new Promise(function(resolve, reject) { $.get("http://api.github.com/repos/facebook/react/forks", function(data) { resolve(data) }) }) } var getCb = function(data) { alert(data[0].owner.login) } initApp() .then(readyCb) .then(clickCb) .then(getCb)
用對象將回調(diào)扁平還好,Promise是什么鬼。不是比回調(diào)還惡心,好吧,示例確實是這樣。其實之所以用Promise除了將回調(diào)轉(zhuǎn)成鏈式調(diào)用以外,主要還是為了用它的reject函數(shù)獲取回調(diào)中的錯誤。像示例這種一路resolve的,沒必要這么用。這里只是提一句。
如果希望了解更多關(guān)于回調(diào)相關(guān)的知識,可以看看Promise, generator, async與ES6這篇文章。
重復查詢:$(document.body).append("") $(".baaron").click(function() {}) // 更好的方式 $("") .appendTo(document.body) .click(function() {})選擇器:
對于jq的選擇器還有許多要注意的問題,因為jq的選擇器是從右向左查詢,所以請記住一個“左輕右重”的原則:
// 請看下面兩個選擇器 $("div.foo .bar") $(".foo span.bar") //右邊更明確一點,會好不少 // 當左邊確實要比右邊明確的時候這么干 $("#foo .bar") $("#foo").find(".bar") // 尤其避免使用通配符 $("#foo > *") $("#foo").children() // 有些通配符是隱式的 $(".foo :radio") $(".foo *:radio") //和上邊一樣的 $(".foo input:radio") //改成這樣聊聊依賴:
接下來,讓我們從優(yōu)化一段jq代碼開始,聊聊js中的依賴
$("#button").click(function() { $.get("http://xxxx", function(data) { $("#page").html(data.abc) }) })
這段代碼有以下問題:
click事件綁定的匿名函數(shù)難以重復利用,也很難測試
click回調(diào)的匿名函數(shù)中的$是全局變量,ajax請求回調(diào)的匿名函數(shù)中的$("#page")也是用到了$這一全局變量,全局變量應該是要避免的
回調(diào)的問題前面也說過了,這里的回調(diào)還很清楚不至于說到地獄的程度
現(xiàn)在我們把代碼這樣改寫:
var downJSON = function() { $.get("http://xxxx", function(data) { $("#page").html(data.abc) }) } $("#button").click(downJSON)
現(xiàn)在匿名函數(shù)被我們拿出來了,可以重用了,但還是難以測試,且涵蓋全局變量。
繼續(xù):
var downJSON = function($, $el) { $.get("http://xxxx", function(data) { $el.html(data.abc) }) } $("#button").click(function() { downJSON($, $("#page")) })
這樣改寫以后,沒有了全局變量,函數(shù)已經(jīng)獨立出去。換一種說法就是,我們?nèi)コ撕瘮?shù)中的隱式依賴(前面例子中的函數(shù)要運行需要全局變量$,但沒有從函數(shù)聲明中表現(xiàn)出來,我們稱其為隱式依賴),現(xiàn)在,函數(shù)執(zhí)行所需要的依賴被顯示聲明,使其具有更好的可控性。前端的依賴管理如今是一個很流行的話題,不過在這里就不廢話了。
奇技淫巧:最后,對于幾種比較常見的寫法,我們也可以使用一些奇技淫巧,或能使代碼更短,或能使代碼更為易讀:
簡化條件語句:// 常見的寫法 if(!data) { data = {} } // 簡化 data = data || {}
你可能覺得這不值一提,但可能有些時候你寫著寫著就忽視了。比如,js數(shù)組去重的4個方法中的第二個方法,就可以應用這個技巧:
// 原來的代碼 Array.prototype.unique2 = function() { var hashTable = {},res=[]; //n為hash表,r為臨時數(shù)組 for(var i = 0; i < this.length; i++) { //遍歷當前數(shù)組 if (!hashTable[this[i]]) { //如果hash表中沒有當前項 res.push(this[i]); //把當前數(shù)組的當前項push到臨時數(shù)組里面 hashTable[this[i]] = true; //存入hash表 } } return res; } // 應用此技巧 Array.prototype.unique2 = function() { var hashTable = {}, res = [] for(var i = 0; i < this.length; i++) { !hashTable[this[i]] ? res.push(this[i]) : null hashTable[this[i]] = hashTable[this[i]] || true } return res }
寫成這樣也未必說是優(yōu)化,目測判斷邏輯還多了一個哈哈,但是嵌套少了一層,怎么說呢,自行決定吧。
下面展示的一個技巧和上面這個也差不多:
// 正常寫法 if(type === "foo" || type === "bar") {} // 用對象有三種方法 // 方法1 if(({foo: 1, bar: 1})[type]) {} // type === "toString"可以繞過驗證 // 方法2 if(type in ({foo: 1, bar: 1})) {} // 和上一種等價但是慢點 // 方法3 if(({foo: 1, bar: 1}).hasOwnProperty(type)) {} // 最嚴密,也最慢 // 用正則 if(/^(foo|bar)$/.test(type)) {}
這種技巧的話,使用與否同樣是自己決定。很多有意思的東西,都是自己想著玩的,有些情況,我們倒不如好好寫成switch - case,都看的懂,也挺清晰。
總結(jié)兩句,雖說jQuery庫和新式的框架相比老了,但我覺得它在DOM操作上真的做到了一個極致。我相信很長一段時間,前端開發(fā)人員入門,還是要從它開始的。個人認為jq不適應時代的原因,是因為它本身也僅僅限于DOM操作,沒有其他限制,以至于當應用復雜時,你完全控制不住你的頁面。當你用上流行的框架,按照他們的Best Practice去組織代碼,我想你剛剛開始的時候,一定會懷念jQuery這個溺愛你的老朋友的。
參考鏈接:反模式 - 學用 JavaScript 設計模式 - 極客學院
jQuery Anti-Patterns for Performance & Compression
Patterns of Large-Scale JavaScript Applications
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/78818.html
摘要:由此看來,的官方文檔就把當成內(nèi)置函數(shù),這個認識錯誤是有根源的等到的時候,官方把錯誤改正過來了,然而改得并不徹底。使用進行判斷,結(jié)果為的才是內(nèi)置函數(shù)。 showImg(https://segmentfault.com/img/bVbm3Bu?w=5184&h=3456);有群友問過,是什么原因使我開始寫技術(shù)公眾號,又是什么動力讓我堅持寫的。 在我看來,寫作是一件不能敷衍的事,通過寫作來學...
摘要:知識點回顧,上次主要說了函數(shù)式和面向?qū)ο螅钍胶晚憫剑到y(tǒng)和系統(tǒng)的差別。以內(nèi)聯(lián)的形式使用。響應式中的設計模式觀察者模式在這種模式中,一個對象維持一系列依賴于它的對象,將有關(guān)的狀態(tài)變更自動的通知給它們。 知識點回顧,上次主要說了函數(shù)式和面向?qū)ο螅钍胶晚憫剑琾ush 系統(tǒng)和 pull 系統(tǒng)的差別。在編程范式,風格之外,設計模式也是在程序設計中時時刻刻都在使用的東西,今天主要就討論...
閱讀 1264·2021-10-18 13:32
閱讀 2333·2021-09-24 09:47
閱讀 1323·2021-09-23 11:22
閱讀 2463·2019-08-30 14:06
閱讀 571·2019-08-30 12:48
閱讀 1997·2019-08-30 11:03
閱讀 535·2019-08-29 17:09
閱讀 2462·2019-08-29 14:10