關(guān)于我們
書單推薦
新書推薦
|
JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐
《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》在尊重《設(shè)計(jì)模式》原意的同時(shí),針對(duì)JavaScript語(yǔ)言特性全面介紹了更適合JavaScript程序員的了16個(gè)常用的設(shè)計(jì)模式,講解了JavaScript面向?qū)ο蠛秃瘮?shù)式編程方面的基礎(chǔ)知識(shí),介紹了面向?qū)ο蟮脑O(shè)計(jì)原則及其在設(shè)計(jì)模式中的體現(xiàn),還分享了面向?qū)ο缶幊碳记珊腿粘i_發(fā)中的代碼重構(gòu)!禞avaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》將教會(huì)你如何把經(jīng)典的設(shè)計(jì)模式應(yīng)用到JavaScript語(yǔ)言中,編寫出優(yōu)美高效、結(jié)構(gòu)化和可維護(hù)的代碼。
適讀人群 :適合初中級(jí)Web前端開發(fā)人員閱讀。
騰訊前端Alloy Team團(tuán)隊(duì)出品,資深前端工程師曾探力作 全面涵蓋專門針對(duì)JavaScript的16個(gè)設(shè)計(jì)模式 深入剖析面向?qū)ο笤O(shè)計(jì)原則、編程技巧及代碼重構(gòu) 設(shè)計(jì)模式是軟件設(shè)計(jì)中經(jīng)過了大量實(shí)際項(xiàng)目驗(yàn)證的可復(fù)用的優(yōu)秀解決方案,它有助于程序員寫出可復(fù)用和可維護(hù)性高的程序。許多優(yōu)秀的JavaScript開源框架都運(yùn)用了不少設(shè)計(jì)模式,越來越多的程序員從設(shè)計(jì)模式中獲益,也許是改善了自己編寫的某個(gè)軟件,也許是更好地理解了面向?qū)ο蟮木幊趟枷。無(wú)論如何,系統(tǒng)地學(xué)習(xí)設(shè)計(jì)模式都會(huì)令你受益匪淺。
《設(shè)計(jì)模式》一書自1995年成書一來,一直是程序員談?wù)摰摹案叨恕痹掝}之一。許多程序員從設(shè)計(jì)模式中學(xué)到了設(shè)計(jì)軟件的靈感,或者找到了問題的解決方案。在社區(qū)中,既有人對(duì)模式無(wú)比崇拜,也有人對(duì)模式充滿誤解。有些程序員把設(shè)計(jì)模式視為圣經(jīng),唯模式至上;有些人卻認(rèn)為設(shè)計(jì)模式只在C++或者Java中有用武之地,JavaScript這種動(dòng)態(tài)語(yǔ)言根本就沒有設(shè)計(jì)模式一說。
那么,在進(jìn)入設(shè)計(jì)模式的學(xué)習(xí)之前,我們最好還是從模式的起源說起,分別聽聽這些不同的聲音。 設(shè)計(jì)模式并非是軟件開發(fā)的專業(yè)術(shù)語(yǔ)。實(shí)際上,“模式”最早誕生于建筑學(xué)。20世紀(jì)70年代,哈佛大學(xué)建筑學(xué)博士Christopher Alexander和他的研究團(tuán)隊(duì)花了約20年的時(shí)間,研究了為解決同一個(gè)問題而設(shè)計(jì)出的不同建筑結(jié)構(gòu),從中發(fā)現(xiàn)了那些高質(zhì)量設(shè)計(jì)中的相似性,并且用“模式”來指代這種相似性。 受Christopher Alexander工作的啟發(fā),Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides四人(人稱Gang Of Four ,GoF)把這種“模式”觀點(diǎn)應(yīng)用于面向?qū)ο蟮能浖O(shè)計(jì)中,并且總結(jié)了23種常見的軟件開發(fā)設(shè)計(jì)模式,錄入《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書。 設(shè)計(jì)模式的定義是:在面向?qū)ο筌浖O(shè)計(jì)過程中針對(duì)特定問題的簡(jiǎn)潔而優(yōu)雅的解決方案。 通俗一點(diǎn)說,設(shè)計(jì)模式是在某種場(chǎng)合下對(duì)某個(gè)問題的一種解決方案。如果再通俗一點(diǎn)說,設(shè)計(jì)模式就是給面向?qū)ο筌浖_發(fā)中的一些好的設(shè)計(jì)取個(gè)名字。 GoF成員之一 John Vlissides在他的另一本關(guān)于設(shè)計(jì)模式的著作《設(shè)計(jì)模式沉思錄》中寫過這樣一段話: 設(shè)想有一個(gè)電子愛好者,雖然他沒有經(jīng)過正規(guī)的培訓(xùn),但是卻日積月累地設(shè)計(jì)并制造出許多有用的電子設(shè)備:業(yè)余無(wú)線電、蓋革計(jì)數(shù)器、報(bào)警器等。有一天這個(gè)愛好者決定重新回到學(xué)校去攻讀電子學(xué)學(xué)位,來讓自己的才能得到真實(shí)的認(rèn)可。隨著課程的展開,這個(gè)愛好者突然發(fā)現(xiàn)課程內(nèi)容都似曾相識(shí)。似曾相識(shí)的并不是術(shù)語(yǔ)或者表述的方式,而是背后的概念。這個(gè)愛好者不斷學(xué)到一些名稱和原理,雖然這些名稱和原理原來他不知道,但事實(shí)上他多年來一直都在使用。整個(gè)過程只不過是一個(gè)接一個(gè)的頓悟。 軟件開發(fā)中的設(shè)計(jì)也是如此。這些“好的設(shè)計(jì)”并不是GoF發(fā)明的,而是早已存在于軟件開發(fā)中。一個(gè)稍有經(jīng)驗(yàn)的程序員也許在不知不覺中數(shù)次使用過這些設(shè)計(jì)模式。GoF最大的功績(jī)是把這些“好的設(shè)計(jì)”從浩瀚的面向?qū)ο笫澜缰刑暨x出來,并且給予它們一個(gè)好聽又好記的名字。 那么,給模式一個(gè)名字有什么意義呢?上述故事中的電子愛好者在未進(jìn)入學(xué)校之前,一點(diǎn)都不知道這些關(guān)于電器的概念有一些特定的名稱,但這不妨礙他制造出一些電子設(shè)備。 實(shí)際上給“模式”取名的意義非常重要。人類可以走到生物鏈頂端的前兩個(gè)原因分別是會(huì)“使用名字”和“使用工具”。在軟件設(shè)計(jì)中,一個(gè)好的設(shè)計(jì)方案有了名字之后,才能被更好地傳播,人們才有更多的機(jī)會(huì)去分享和學(xué)習(xí)它們。 也許這個(gè)小故事可以說明名字對(duì)于模式的重要性:假設(shè)你是一名足球教練,正在球場(chǎng)邊指揮一場(chǎng)足球賽。通過一段時(shí)間的觀察后,發(fā)現(xiàn)對(duì)方的后衛(wèi)技術(shù)精湛,身體強(qiáng)壯,但邊后衛(wèi)速度較慢,中后衛(wèi)身高和頭球都非常一般。于是你在場(chǎng)邊大聲指揮隊(duì)員:“用速度突破對(duì)方邊后衛(wèi)之后,往球門方向踢出高球,中路接應(yīng)隊(duì)員搶點(diǎn)頭球攻門! 在機(jī)會(huì)稍縱即逝的足球場(chǎng)上,教練這樣費(fèi)盡口舌地指揮隊(duì)員比賽無(wú)疑是荒謬的。實(shí)際上這種戰(zhàn)術(shù)有一個(gè)名字叫作“下底傳中”。正因?yàn)閼?zhàn)術(shù)有了對(duì)應(yīng)的名字,在球場(chǎng)上教練可以很方便地和球員交流!跋碌讉髦小边@種戰(zhàn)術(shù)即是足球場(chǎng)上的一種“模式”。 在軟件設(shè)計(jì)中亦是如此。我們都知道設(shè)計(jì)經(jīng)驗(yàn)非常重要。也許我們都有過這種感覺:這個(gè)問題發(fā)生的場(chǎng)景似曾相識(shí),以前我遇到并解決過這個(gè)問題,但是我不知道怎么跟別人去描述它。我們非常希望給這個(gè)問題出現(xiàn)的場(chǎng)景和解決方案取一個(gè)統(tǒng)一的名字,當(dāng)別人聽到這個(gè)名字的時(shí)候,便知道我想表達(dá)什么。比如一個(gè)JavaScript新手今天學(xué)會(huì)了編寫each函數(shù),each函數(shù)用來迭代一個(gè)數(shù)組。他很難想到這個(gè)each函數(shù)其實(shí)就是迭代器模式。于是他向別人描述這個(gè)函數(shù)結(jié)構(gòu)和意圖的時(shí)候會(huì)遇到困難,而一旦大家對(duì)迭代器模式這個(gè)名字達(dá)成了共識(shí),剩下的交流便是自然而然的事情。 學(xué)習(xí)模式的作用 小說家很少?gòu)念^開始設(shè)計(jì)劇情,足球教練也很少?gòu)念^開始發(fā)明戰(zhàn)術(shù),他們總是沿襲一些已經(jīng)存在的模式。當(dāng)足球教練看到對(duì)方邊后衛(wèi)速度慢,中后衛(wèi)身高矮時(shí),自然會(huì)想到“下底傳中”這種模式。 同樣,在軟件設(shè)計(jì)中,模式是一些經(jīng)過了大量實(shí)際項(xiàng)目驗(yàn)證的優(yōu)秀解決方案。熟悉這些模式的程序員,對(duì)某些模式的理解也許形成了條件反射。當(dāng)合適的場(chǎng)景出現(xiàn)時(shí),他們可以很快地找到某種模式作為解決方案。 比如,當(dāng)他們看到系統(tǒng)中存在一些大量的相似對(duì)象,這些對(duì)象給系統(tǒng)的內(nèi)存帶來了較大的負(fù)擔(dān)。如果他們熟悉享元模式,那么第一時(shí)間就可以想到用享元模式來優(yōu)化這個(gè)系統(tǒng)。再比如,系統(tǒng)中某個(gè)接口的結(jié)構(gòu)已經(jīng)不能符合目前的需求,但他們又不想去改動(dòng)這個(gè)被灰塵遮住的老接口,一個(gè)熟悉模式的程序員將很快地找到適配器模式來解決這個(gè)問題。 如果我們還沒有學(xué)習(xí)全部的模式,當(dāng)遇到一個(gè)問題時(shí),我們冥冥之中覺得這個(gè)問題出現(xiàn)的幾率很高,說不定別人也遇到過同樣的問題,并且已經(jīng)把它整理成了模式,提供了一種通用的解決方案。這時(shí)候去翻翻《設(shè)計(jì)模式》這本書也許就會(huì)有意外的收獲。 模式在不同語(yǔ)言之間的區(qū)別 《設(shè)計(jì)模式》一書的副標(biāo)題是“可復(fù)用面向?qū)ο筌浖幕A(chǔ)”!对O(shè)計(jì)模式》這本書完全是從面向?qū)ο笤O(shè)計(jì)的角度出發(fā)的,通過對(duì)封裝、繼承、多態(tài)、組合等技術(shù)的反復(fù)使用,提煉出一些可重復(fù)使用的面向?qū)ο笤O(shè)計(jì)技巧。所以有一種說法是設(shè)計(jì)模式僅僅是就面向?qū)ο蟮恼Z(yǔ)言而言的。 《設(shè)計(jì)模式》最初講的確實(shí)是靜態(tài)類型語(yǔ)言中的設(shè)計(jì)模式,原書大部分代碼由C++寫成,但設(shè)計(jì)模式實(shí)際上是解決某些問題的一種思想,與具體使用的語(yǔ)言無(wú)關(guān)。模式社區(qū)和語(yǔ)言一直都在發(fā)展,如今,除了主流的面向?qū)ο笳Z(yǔ)言,函數(shù)式語(yǔ)言的發(fā)展也非常迅猛。在函數(shù)式或者其他編程范型的語(yǔ)言中,設(shè)計(jì)模式依然存在。 人類飛上天空需要借助飛機(jī)等工具,而鳥兒天生就有翅膀。在Dota游戲里,牛頭人的人生目標(biāo)是買一把跳刀(跳刀可以使用跳躍技能),而敵法師天生就有跳躍技能。因?yàn)檎Z(yǔ)言的不同,一些設(shè)計(jì)模式在另外一些語(yǔ)言中的實(shí)現(xiàn)也許跟我們?cè)凇对O(shè)計(jì)模式》一書中看到的大相徑庭,這一點(diǎn)也不令人意外。 Google的研究總監(jiān)Peter Norvig早在1996年一篇名為“動(dòng)態(tài)語(yǔ)言設(shè)計(jì)模式”的演講中,就指出了GoF所提出的23種設(shè)計(jì)模式,其中有16種在Lisp語(yǔ)言中已經(jīng)是天然的實(shí)現(xiàn)。比如,Command模式在Java中需要一個(gè)命令類,一個(gè)接收者類,一個(gè)調(diào)用者類。Command模式把運(yùn)算塊封裝在命令對(duì)象的方法內(nèi),成為該對(duì)象的行為,并把命令對(duì)象四處傳遞。但在Lisp或者JavaScript這些把函數(shù)當(dāng)作一等對(duì)象的語(yǔ)言中,函數(shù)便能封裝運(yùn)算塊,并且函數(shù)可以被當(dāng)成對(duì)象一樣四處傳遞,這樣一來,命令模式在Lisp或者JavaScript中就成為了一種隱形的模式。 在Java這種靜態(tài)編譯型語(yǔ)言中,無(wú)法動(dòng)態(tài)地給已存在的對(duì)象添加職責(zé),所以一般通過包裝類的方式來實(shí)現(xiàn)裝飾者模式。但在JavaScript這種動(dòng)態(tài)解釋型語(yǔ)言中,給對(duì)象動(dòng)態(tài)添加職責(zé)是再簡(jiǎn)單不過的事情。這就造成了JavaScript語(yǔ)言的裝飾者模式不再關(guān)注于給對(duì)象動(dòng)態(tài)添加職責(zé),而是關(guān)注于給函數(shù)動(dòng)態(tài)添加職責(zé)。 設(shè)計(jì)模式的適用性 設(shè)計(jì)模式被一些人認(rèn)為只是夸夸其談的東西,這些人認(rèn)為設(shè)計(jì)模式并沒有多大用途。畢竟我們用普通的方法就能解決的問題,使用設(shè)計(jì)模式可能會(huì)增加復(fù)雜度,或帶來一些額外的代碼。如果對(duì)一些設(shè)計(jì)模式使用不當(dāng),事情還可能變得更糟。 從某些角度來看,設(shè)計(jì)模式確實(shí)有可能帶來代碼量的增加,或許也會(huì)把系統(tǒng)的邏輯搞得更復(fù)雜。但軟件開發(fā)的成本并非全部在開發(fā)階段,設(shè)計(jì)模式的作用是讓人們寫出可復(fù)用和可維護(hù)性高的程序。假設(shè)有一個(gè)空房間,我們要日復(fù)一日地往里面放一些東西。最簡(jiǎn)單的辦法當(dāng)然是把這些東西直接扔進(jìn)去,但是時(shí)間久了,就會(huì)發(fā)現(xiàn)很難從這個(gè)房子里找到自己想要的東西,要調(diào)整某幾樣?xùn)|西的位置也不容易。所以在房間里做一些柜子也許是個(gè)更好的選擇,雖然柜子會(huì)增加我們的成本,但它可以在維護(hù)階段為我們帶來好處。使用這些柜子存放東西的規(guī)則,或許就是一種模式。 所有設(shè)計(jì)模式的實(shí)現(xiàn)都遵循一條原則,即“找出程序中變化的地方,并將變化封裝起來”。一個(gè)程序的設(shè)計(jì)總是可以分為可變的部分和不變的部分。當(dāng)我們找出可變的部分,并且把這些部分封裝起來,那么剩下的就是不變和穩(wěn)定的部分。這些不變和穩(wěn)定的部分是非常容易復(fù)用的。這也是設(shè)計(jì)模式為什么描寫的是可復(fù)用面向?qū)ο筌浖A(chǔ)的原因。 設(shè)計(jì)模式被人誤解的一個(gè)重要原因是人們對(duì)它的誤用和濫用,比如將一些模式用在了錯(cuò)誤的場(chǎng)景中,或者說在不該使用模式的地方刻意使用模式。特別是初學(xué)者在剛學(xué)會(huì)使用一個(gè)模式時(shí),恨不得把所有的代碼都用這個(gè)模式來實(shí)現(xiàn)。錘子理論在這里體現(xiàn)得很明顯:當(dāng)我們有了一把錘子,看什么都是釘子。拿足球比賽的例子來說,我們的目標(biāo)只是進(jìn)球,“下底傳中”這種“模式”僅僅是達(dá)到進(jìn)球目標(biāo)的一種手段。當(dāng)我們面臨密集防守時(shí),下底傳中或許是一種好的選擇;但如果我們的球員獲得了一個(gè)直接面對(duì)對(duì)方守門員的單刀機(jī)會(huì),那么是否還要把球先傳向邊路隊(duì)友,再由邊路隊(duì)友來一個(gè)邊路傳中呢?答案是顯而易見的,模式應(yīng)該用在正確的地方。而哪些才算正確的地方,只有在我們深刻理解了模式的意圖之后,再結(jié)合項(xiàng)目的實(shí)際場(chǎng)景才會(huì)知道。 分辨模式的關(guān)鍵是意圖而不是結(jié)構(gòu) 在設(shè)計(jì)模式的學(xué)習(xí)中,有人經(jīng)常發(fā)出這樣的疑問:代理模式和裝飾者模式,策略模式和狀態(tài)模式,策略模式和智能命令模式,這些模式的類圖看起來幾乎一模一樣,它們到底有什么區(qū)別? 實(shí)際上這種情況是普遍存在的,許多模式的類圖看起來都差不多,模式只有放在具體的環(huán)境下才有意義。比如我們的手機(jī),把它當(dāng)電話的時(shí)候,它就是電話;把它當(dāng)鬧鐘的時(shí)候,它就是鬧鐘;用它玩游戲的時(shí)候,它就是游戲機(jī)。我看到有人手中拿著iPhone18,但那實(shí)際上可能只是一個(gè)吹風(fēng)機(jī)。有很多模式的類圖和結(jié)構(gòu)確實(shí)很相似,但這不太重要,辨別模式的關(guān)鍵是這個(gè)模式出現(xiàn)的場(chǎng)景,以及為我們解決了什么問題。 對(duì)JavaScript設(shè)計(jì)模式的誤解 雖然JavaScript是一門完全面向?qū)ο蟮恼Z(yǔ)言,但在很長(zhǎng)一段時(shí)間內(nèi),JavaScript在人們的印象中只是用來驗(yàn)證表單,或者完成一些簡(jiǎn)單動(dòng)畫特效的腳本語(yǔ)言。在JavaScript語(yǔ)言上運(yùn)用設(shè)計(jì)模式難免顯得小題大做。但目前JavaScript已成為最流行的語(yǔ)言之一,在許多大型Web項(xiàng)目中,JavaScript代碼的數(shù)量已經(jīng)非常多了。我們絕對(duì)有必要把一些優(yōu)秀的設(shè)計(jì)模式借鑒到JavaScript這門語(yǔ)言中。許多優(yōu)秀的JavaScript開源框架也運(yùn)用了不少設(shè)計(jì)模式。 J avaScript設(shè)計(jì)模式的社區(qū)目前還幾乎是一片荒漠。網(wǎng)絡(luò)上有一些討論JavaScript設(shè)計(jì)模式的資料和文章,但這些資料和文章大多都存在兩個(gè)問題。 第一個(gè)問題是習(xí)慣把靜態(tài)類型語(yǔ)言的設(shè)計(jì)模式照搬到JavaScript中,比如有人為了模擬JavaScript版本的工廠方法(Factory Method)模式,而生硬地把創(chuàng)建對(duì)象的步驟延遲到子類中。實(shí)際上,在Java等靜態(tài)類型語(yǔ)言中,讓子類來“決定”創(chuàng)建何種對(duì)象的原因是為了讓程序迎合依賴倒置原則(DIP)。在這些語(yǔ)言中創(chuàng)建對(duì)象時(shí),先解開對(duì)象類型之間的耦合關(guān)系非常重要,這樣才有機(jī)會(huì)在將來讓對(duì)象表現(xiàn)出多態(tài)性。 而在JavaScript這種類型模糊的語(yǔ)言中,對(duì)象多態(tài)性是天生的,一個(gè)變量既可以指向一個(gè)類,又可以隨時(shí)指向另外一個(gè)類。JavaScript不存在類型耦合的問題,自然也沒有必要刻意去把對(duì)象“延遲”到子類創(chuàng)建,也就是說,JavaScript實(shí)際上是不需要工廠方法模式的。模式的存在首先是能為我們解決什么問題,這種牽強(qiáng)的模擬只會(huì)讓人覺得設(shè)計(jì)模式既難懂又沒什么用處。 另一個(gè)問題是習(xí)慣根據(jù)模式的名字去臆測(cè)該模式的一切。比如命令模式本意是把請(qǐng)求封裝到對(duì)象中,利用命令模式可以解開請(qǐng)求發(fā)送者和請(qǐng)求接受者之間的耦合關(guān)系。但命令模式經(jīng)常被人誤解為只是一個(gè)名為execute的普通方法調(diào)用。這個(gè)方法除了叫作execute之外,其實(shí)并沒有看出其他用處。所以許多人會(huì)誤會(huì)命令模式的意圖,以為它其實(shí)沒什么用處,從而聯(lián)想到其他設(shè)計(jì)模式也沒有用處。 這些誤解都影響了設(shè)計(jì)模式在JavaScript語(yǔ)言中的發(fā)展。 模式的發(fā)展 前面說過,模式的社區(qū)一直在發(fā)展。GoF在1995年提出了23種設(shè)計(jì)模式。但模式不僅僅局限于這23種。在近20年的時(shí)間里,也許有更多的模式已經(jīng)被人發(fā)現(xiàn)并總結(jié)了出來。比如一些JavaScript圖書中會(huì)提到模塊模式、沙箱模式等。這些“模式”能否被世人公認(rèn)并流傳下來,還有待時(shí)間驗(yàn)證。不過某種解決方案要成為一種模式,還是有幾個(gè)原則要遵守的。這幾個(gè)原則即是“再現(xiàn)”“教學(xué)”和“能夠以一個(gè)名字來描述這種模式”。 不管怎樣,在一些模式被公認(rèn)并流行起來之前,需要慎重地冠之以某種模式的名稱。否則模式也許很容易泛濫,導(dǎo)致人人都在發(fā)明模式,這反而增加了交流的難度。說不準(zhǔn)哪天我們就能聽到有人說全局變量模式、加模式、減模式等。 在《設(shè)計(jì)模式》出版后的近20年里,也出現(xiàn)了另外一批講述設(shè)計(jì)模式的優(yōu)秀讀物。其中許多都獲得過Jolt大獎(jiǎng)。數(shù)不清的程序員從設(shè)計(jì)模式中獲益,也許是改善了自己編寫的某個(gè)軟件,也許是從設(shè)計(jì)模式的學(xué)習(xí)中更好地理解了面向?qū)ο缶幊趟枷。無(wú)論如何,相信對(duì)我們這些大多數(shù)的普通程序員來說,系統(tǒng)地學(xué)習(xí)設(shè)計(jì)模式并沒有壞處,相反,你會(huì)在模式的學(xué)習(xí)過程中受益匪淺。
曾探,2007年畢業(yè)于吉林大學(xué)軟件學(xué)院。就職于國(guó)內(nèi)知名前端團(tuán)隊(duì)騰訊AlloyTeam,高級(jí)工程師。曾參與WebQQ、QQ群、Q+開發(fā)者網(wǎng)站、微云、QQ興趣部落等大型前端項(xiàng)目的開發(fā)。有過Java、Python和JavaScript的開發(fā)經(jīng)驗(yàn),業(yè)余作品有HTML5版街頭霸王等。平時(shí)喜歡電影和音樂,業(yè)余時(shí)間也是一名健身教練。
第一部分 基礎(chǔ)知識(shí)
第1章 面向?qū)ο蟮腏avaScript 1.1 動(dòng)態(tài)類型語(yǔ)言和鴨子類型 1.2 多態(tài) 1.3 封裝 1.4 原型模式和基于原型繼承的JavaScript對(duì)象系統(tǒng) 第2章 this、call和apply 2.1 this 2.2 call和apply 第3章 閉包和高階函數(shù) 3.1 閉包 3.2 高階函數(shù) 3.3 小結(jié) 第二部分 設(shè)計(jì)模式 第4章 單例模式 4.1 實(shí)現(xiàn)單例模式 4.2 透明的單例模式 4.3 用代理實(shí)現(xiàn)單例模式 4.4 JavaScript中的單例模式 4.5 惰性單例 4.6 通用的惰性單例 4.7 小結(jié) 第5章 策略模式 5.1 使用策略模式計(jì)算獎(jiǎng)金 5.2 JavaScript 版本的策略模式 5.3 多態(tài)在策略模式中的體現(xiàn) 5.4 使用策略模式實(shí)現(xiàn)緩動(dòng)動(dòng)畫 5.5 更廣義的"算法" 5.6 表單校驗(yàn) 5.7 策略模式的優(yōu)缺點(diǎn) 5.8 一等函數(shù)對(duì)象與策略模式 5.9 小結(jié) 第6章 代理模式 6.1 第一個(gè)例子--小明追MM的故事 6.2 保護(hù)代理和虛擬代理 6.3 虛擬代理實(shí)現(xiàn)圖片預(yù)加載 6.4 代理的意義 6.5 代理和本體接口的一致性 6.6 虛擬代理合并HTTP 請(qǐng)求 6.7 虛擬代理在惰性加載中的應(yīng)用 6.8 緩存代理 6.9 用高階函數(shù)動(dòng)態(tài)創(chuàng)建代理 6.10 其他代理模式 6.11 小結(jié) 第7章 迭代器模式 7.1 jQuery 中的迭代器 7.2 實(shí)現(xiàn)自己的迭代器 7.3 內(nèi)部迭代器和外部迭代器 7.4 迭代類數(shù)組對(duì)象和字面量對(duì)象 7.5 倒序迭代器 7.6 中止迭代器 7.7 迭代器模式的應(yīng)用舉例 7.8 小結(jié) 第8章 發(fā)布-訂閱模式 8.1 現(xiàn)實(shí)中的發(fā)布-訂閱模式 8.2 發(fā)布-訂閱模式的作用 8.3 DOM 事件 8.4 自定義事件 8.5 發(fā)布-訂閱模式的通用實(shí)現(xiàn) 8.6 取消訂閱的事件 8.7 真實(shí)的例子--網(wǎng)站登錄 8.8 全局的發(fā)布-訂閱對(duì)象 8.9 模塊間通信 8.10 必須先訂閱再發(fā)布嗎 8.11 全局事件的命名沖突 8.12 JavaScript實(shí)現(xiàn)發(fā)布-訂閱模式的便利性 8.13 小結(jié) 第9章 命令模式 9.1 命令模式的用途 9.2 命令模式的例子--菜單程序 9.3 JavaScript中的命令模式 9.4 撤銷命令 9.5 撤消和重做 9.6 命令隊(duì)列 9.7 宏命令 9.8 智能命令與傻瓜命令 9.9 小結(jié) 第10章 組合模式 10.1 回顧宏命令 10.2 組合模式的用途 10.3 請(qǐng)求在樹中傳遞的過程 10.4 更強(qiáng)大的宏命令 10.5 抽象類在組合模式中的作用 10.6 透明性帶來的安全問題 10.7 組合模式的例子--掃描文件夾 10.8 一些值得注意的地方 10.9 引用父對(duì)象 10.10 何時(shí)使用組合模式 10.11 小結(jié) 第11章 模板方法模式 11.1 模板方法模式的定義和組成 11.2 第一個(gè)例子--Coffee or Tea 11.3 抽象類 11.4 模板方法模式的使用場(chǎng)景 11.5 鉤子方法 11.6 好萊塢原則 11.7 真的需要"繼承"嗎 11.8 小結(jié) 第12章 享元模式 12.1 初識(shí)享元模式 12.2 內(nèi)部狀態(tài)與外部狀態(tài) 12.3 享元模式的通用結(jié)構(gòu) 12.4 文件上傳的例子 12.5 享元模式的適用性 12.6 再談內(nèi)部狀態(tài)和外部狀態(tài) 12.7 對(duì)象池 12.8 小結(jié) 第13章 職責(zé)鏈模式 13.1 現(xiàn)實(shí)中的職責(zé)鏈模式 13.2 實(shí)際開發(fā)中的職責(zé)鏈模式 13.3 用職責(zé)鏈模式重構(gòu)代碼 13.4 靈活可拆分的職責(zé)鏈節(jié)點(diǎn) 13.5 異步的職責(zé)鏈 13.6 職責(zé)鏈模式的優(yōu)缺點(diǎn) 13.7 用AOP 實(shí)現(xiàn)職責(zé)鏈 13.8 用職責(zé)鏈模式獲取文件上傳對(duì)象 13.9 小結(jié) 第14章 中介者模式 14.1 現(xiàn)實(shí)中的中介者 14.2 中介者模式的例子--泡泡堂游戲 14.3 中介者模式的例子--購(gòu)買商品 14.4 小結(jié) 第15章 裝飾者模式 15.1 模擬傳統(tǒng)面向?qū)ο笳Z(yǔ)言的裝飾者模式 15.2 裝飾者也是包裝器 15.3 回到JavaScript 的裝飾者 15.4 裝飾函數(shù) 15.5 用AOP 裝飾函數(shù) 15.6 AOP 的應(yīng)用實(shí)例 15.7 裝飾者模式和代理模式 15.8 小結(jié) 第16章 狀態(tài)模式 16.1 初識(shí)狀態(tài)模式 16.2 狀態(tài)模式的定義 16.3 狀態(tài)模式的通用結(jié)構(gòu) 16.4 缺少抽象類的變通方式 16.5 另一個(gè)狀態(tài)模式示例--文件上傳 16.6 狀態(tài)模式的優(yōu)缺點(diǎn) 16.7 狀態(tài)模式中的性能優(yōu)化點(diǎn) 16.8 狀態(tài)模式和策略模式的關(guān)系 16.9 JavaScript版本的狀態(tài)機(jī) 16.10 表驅(qū)動(dòng)的有限狀態(tài)機(jī) 16.11 實(shí)際項(xiàng)目中的其他狀態(tài)機(jī) 16.12 小結(jié) 第17章 適配器模式 17.1 現(xiàn)實(shí)中的適配器 17.2 適配器模式的應(yīng)用 17.3 小結(jié) 第三部分 設(shè)計(jì)原則和編程技巧 第18章 單一職責(zé)原則 18.1 設(shè)計(jì)模式中的SRP原則 18.2 何時(shí)應(yīng)該分離職責(zé) 18.3 違反SRP原則 18.4 SRP 原則的優(yōu)缺點(diǎn) 第19章 最少知識(shí)原則 19.1 減少對(duì)象之間的聯(lián)系 19.2 設(shè)計(jì)模式中的LKP原則 19.3 封裝在LKP 原則中的體現(xiàn) 第20章 開放-封閉原則 20.1 擴(kuò)展window.onload函數(shù) 20.2 開放和封閉 20.3 用對(duì)象的多態(tài)性消除條件分支 20.4 找出變化的地方 20.5 設(shè)計(jì)模式中的開放-封閉原則 20.6 開放-封閉原則的相對(duì)性 20.7 接受第一次愚弄 第21章 接口和面向接口編程 21.1 回到Java的抽象類 21.2 interface 21.3 JavaScript 語(yǔ)言是否需要抽象類和interface 21.4 用鴨子類型進(jìn)行接口檢查 21.5 用TypeScript 編寫基于interface的命令模式 第22章 代碼重構(gòu) 22.1 提煉函數(shù) 22.2 合并重復(fù)的條件片段 22.3 把條件分支語(yǔ)句提煉成函數(shù) 22.4 合理使用循環(huán) 22.5 提前讓函數(shù)退出代替嵌套條件分支 22.6 傳遞對(duì)象參數(shù)代替過長(zhǎng)的參數(shù)列表 22.7 盡量減少參數(shù)數(shù)量 22.8 少用三目運(yùn)算符 22.9 合理使用鏈?zhǔn)秸{(diào)用 22.10 分解大型類 22.11 用return退出多重循環(huán) 參考文獻(xiàn)
你還可能感興趣
我要評(píng)論
|