精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

前端優秀實踐之可維護性

開發 前端
編寫可維護的代碼十分重要,因為很多開發者都會花大量時間去維護別人寫的代碼。讓自己的代碼容易維護,可以保證其他開發者更好地完成自己的工作。

在早期網站中,JavaScript主要用于實現一些小型動效或表單驗證。今天的Web應用則動輒成千上萬行JavaScript代碼,用于完成各種各樣復雜的處理。這些變化要求開發者把可維護能力放到重要位置上。正如更傳統意義上的軟件工程師一樣,JavaScript工程師受雇是要為公司創造價值的。現代前端工程師的使命,不僅僅是要保證產品如期上線,更重要的是要隨著時間推移為公司不斷積累知識資產。

[[324237]]

編寫可維護的代碼十分重要,因為很多開發者都會花大量時間去維護別人寫的代碼。實際開發中,從第一行代碼開始寫起的情況是非常少見的。通常都是要在別人的代碼之上來構建自己的工作。讓自己的代碼容易維護,可以保證其他開發者更好地完成自己的工作。

注意:可維護代碼的概念并不止適用于JavaScript,其中很多概念適用于任何編程語言。當然,有部分概念可能確實是特定于JavaScript的。

1. 什么是可維護的代碼

可維護的代碼有幾個特點。通常,說代碼可維護就意味著它具備如下特點。

  • 容易理解:無需求助原始開發者,任何人一看代碼就知道是干什么的,怎么實現的。
  • 符合常識:代碼中的一切都顯得自然而然,無論操作有多么復雜。
  • 容易適配:即使數據發生變化也不用完全重寫。
  • 容易擴展:代碼架構經過認真設計,支持未來擴展核心功能。
  • 容易調試:出問題時,代碼可以給出明確的信息,通過它能直接定位問題。

能夠寫出可維護的JavaScript代碼是一項重要的專業技能。這個技能是一個周末就拼湊一個網站的業余愛好者和對自己所做的一切都深思熟慮的專業開發者的重要區別。

2. 編碼規范

編寫可維護代碼的第一步是認真考慮編碼規范。編碼規范在多數編程語言中都會涉及,簡單上網一搜,就可以找到成千上萬的相關文章。專業組織都會有為開發者建立的編碼規范,旨在讓人寫出更容易維護的代碼。優秀開源項目都有嚴格的編碼規范,能夠讓社區的所有人容易理解代碼的組織。

編碼規范對JavaScript而言非常重要,因為這門語言實在太靈活了。與多數面向對象語言不同,JavaScript并不強迫開發者把任何東西都定義為對象。相反,JavaScript支持任何編程風格,包括傳統的面向對象編程和聲明式編程,以及函數式編程。簡單看幾個開源的JavaScript庫,就會發現有很多方式可以創建對象、定義方法和管理環境。

接下來的幾節會討論制定編碼規范的一些基礎方面。這些主題都很重要,當然每個人的需求不同,實現方式也可以不同。

2.1 可讀性

要想讓代碼容易維護,首先必須讓人容易看懂。可讀性必須考慮代碼是一種文本文件。為此,代碼縮進是保證可讀性的重要基礎。如果所有人都使用相同的縮進,整個項目的代碼就會更容易看懂。縮進通常要使用空格數而不是Tab(制表符)來定義,因為后者在不同文本編輯器中的顯示會有差異。一般來說,縮進都是以4個空格為單位,當然具體多少個可以自己定。

可讀性的另一方面是代碼注釋。在多數編程語言中,廣泛接受的做法是為每個方法都編寫注釋。由于JavaScript可以在代碼中任何地方創建函數,所以這一點容易被忽視。正因為如此,可能給JavaScript中的每個函數都寫注釋才更重要。一般來說,以下這些地方都是應該寫注釋的。

  • 函數和方法。每個函數和方法都應該有注釋來描述其用途,以及完成任務所用的算法。同時,也寫清使用這個函數或方法的前提(假設)、每個參數的含義,以及函數是否返回值(因為通過函數定義看不出來)。
  • 大型代碼塊。多行代碼但用于完成單一任務的,應該在前面給出注釋,把要完成的任務寫清楚。
  • 復雜的算法。如果使用了不同尋常的手法解決了問題,要通過注釋解釋明白。這樣不僅可以幫到別人,也可以讓自己今后再看的時候更快想起來。
  • 使用黑科技。由于瀏覽器之間的差異,JavaScript代碼中通常都會包含一些黑科技。不要假設其他人一看就能明白某個黑科技是為了解決某個瀏覽器的什么問題。如果對某個瀏覽器不能使用正常方式達到目的,那要在注釋里把黑科技的用途寫出來。這樣可以避免別人誤以為黑科技沒有用而把它“修復”掉,結果你已經修好的問題又會復現。

縮進和注釋可以讓代碼更容易理解,將來也更容易維護。

2.2 變量和函數命名

變量和函數的適當命名對于可讀性和可維護性也是至關重要的。由于很多JavaScript開發者都是“草莽”出身,所以很容易用foo、bar命名變量,用doSomething來命名函數。專業JavaScript開發者必須改掉這些積習,這樣才能寫出可維護的代碼。以下是關于命名的通用規則。

  • 變量名應該是名詞,例如car或person。
  • 函數名應該以動詞開始,例如getName()。返回布爾值的函數通常以is開頭,比如isEnabled()。
  • 對變量和函數都使用符合邏輯的名字,不用擔心長度。長名字的問題可以通過后處理和壓縮解決。
  • 變量、函數和方法應該以小寫字母開頭,使用駝峰大小寫形式,如getName()和isPerson。類名應該首字母大寫,比如Person、RequestFactory。常量值應該全部大寫并以下劃線相接,比如REQUEST_TIMEOUT。
  • 名字要盡量用描述性和直觀的詞匯,但不要過于冗長。getName()一看就知道會返回名字,而PersonFactory一看就知道會產生某個Person對象或實例。

要完全避免沒有用的變量名,比如不能表示所包含數據的類型。通過適當命名,代碼讀起來就會像故事,因此更容易理解。

2.3 變量類型透明化

因為JavaScript是松散類型的語言,所以很容易忘記變量包含的數據類型。適當命名可以在某種程度上解決這個問題,但還不夠。有三種方式可以表明變量的數據類型。

第一種方式是通過初始化。定義變量時,應該立即將其初始化為一個將來要使用類型的值。例如,要保存布爾值的變量可以將其初始化為true或false,而要保存數值的變量可以將其初始化為一個數值。再看幾個例子:

  1. // 通過初始化表明變量類型 
  2. let found = false; // Boolean 
  3. let count = -1; // number 
  4. let name = ""; // string 
  5. let person = null; // object 

初始化為特定數據類型的值可以明確表示變量的類型。在ES6之前,初始化方式不適合函數聲明中函數的參數。ES6之后,可以在函數聲明中為參數指定默認值來表明參數類型。

第二種表示變量類型的方式是使用匈牙利表示法。匈牙利表示法指的是在變量名前面前綴一個或多個字符表示數據類型。這種表示法曾經在腳本語言中非常流行,很長時間以來也是JavaScript首選的格式。對于基本數據類型,用o表示對象(object)、s表示字符串(string),i表示整數(integer),f表示浮點數(float)、b表示布爾值(boolean)。下面看幾個例子。

  1. // 使用匈牙利表示法標明數據類型 
  2. let bFound; // Boolean 
  3. let iCount; // integer 
  4. let sName; // string 
  5. let oPerson; // object 

匈牙利表示法也可以應用給函數參數。匈牙利表示法的缺點是讓代碼可讀性有所下降,不夠直觀,破壞了類似句子的自然閱讀流暢性。為此,匈牙利表示法已經被很多開發者拋棄。

最后一種表明數據類型的方式是使用類型注釋。類型注釋放在變量名后面,初始化表達式的前面。基本思路是在變量旁邊使用注釋說明類型,比如:

  1. // 使用類型注釋標明數據類型 
  2. let found /*:Boolean*/ = false; 
  3. let count /*:int*/ = 10; 
  4. let name /*:String*/ = "Nicholas"; 
  5. let person /*:Object*/ = null; 

類型注釋在保持整體可讀性的同時向代碼中注入了類型信息。類型注釋的缺點是不能再使用多行注釋把大型代碼塊注釋掉了。因為類型注釋也是多行注釋,因此會造成干擾,如下面的例子所示:

  1. // 這樣多行注釋不會生效 
  2. /* 
  3. let found /*:Boolean*/ = false; 
  4. let count /*:int*/ = 10; 
  5. let name /*:String*/ = "Nicholas"; 
  6. let person /*:Object*/ = null; 
  7. */ 

這里本來是想使用多行注釋把所有變量聲明都注釋掉。但類型注釋產生了干擾,因為第一個/*(第2行)會與第一個*/(第3行)匹配,結果會導致語法錯誤。如果想注釋掉包含類型注釋的代碼,只能使用單行注釋一行一行地注釋掉每一行(有的編輯器可以自動完成)。

以上是三種標明變量數據類型的最常用方式。每種方式都有優點和缺點,可以根據自己的情況選用。關鍵要看哪一種最適合自己的項目,并保證一致性。

3. 松散耦合

只要應用的某個部分對另一個部分依賴得過于緊密,代碼就會變成強耦合,因而難以維護。典型的問題是在一個對象中直接引用另一個對象。這樣,修改其中一個,可能必須還得修改另一個。緊密耦合的軟件難于維護,肯定需要頻繁地重寫。

考慮到相關的技術,Web應用在某些情況下可能變得過于強耦合。關鍵在于有這個意識,隨時注意不要讓代碼產生強耦合。

3.1 解耦HTML/JavaScript

Web開發中最常見的耦合是HTML/JavaScript耦合。在網頁中,HTML和JavaScript分別代表不同層面的解決方案。HTML是數據,JavaScript是行為。因為它們之間要交互操作,需要通過不同的方式將這兩種技術聯系起來。可惜的是,其中一些方式會導致HTML與JavaScript強耦合。

把JavaScript直接嵌入在HTML中,包括使用<script>元素包含嵌入代碼或使用HTML屬性添加事件處理程序,都會造成強耦合。比如下面的例子:

  1. <!-- 使用<script>造成HTML/JavaScript強耦合 --> 
  2. <script> 
  3.     document.write("Hello world!"); 
  4. </script> 
  5.  
  6. <!-- 使用事件處理程序屬性造成HTML/JavaScript強耦合 --> 
  7. <input type="button" value="Click Me" onclick="doSomething()"/> 

雖然技術上這樣做沒有問題,但實踐中這樣會導致HTML的數據與JavaScript的行為緊密耦合在一起。理想情況下,HTML和JavaScript應該完全分開,通過外部文件引入JavaScript,然后使用DOM添加行為。

HTML與JavaScript強耦合的情況下,每次分析JavaScript的報錯都要首先確定錯誤來自HTML還是JavaScript。而且,這樣也會引入代碼可用性的新錯誤。在這個例子中,用戶可能會在doSomething()函數可用之前點擊按鈕,從而導致JavaScript報錯。由于每次修改按鈕的行為都需要既改HTML又改JavaScript,而實際上只有后者才是有必要修改的。這樣就會降低代碼的可維護性。

在相反的情況下,HTML和JavaScript也會變得強耦合:把HTML包含在JavaScript中。這種情況通常發生在把一段HTML通過innerHTML插入到頁面中,比如:

  1. // HTML緊耦合到了JavaScript 
  2. function insertMessage(msg) { 
  3.   let container = document.getElementById("container"); 
  4.     container.innerHTML = `<div class="msg"> 
  5.       <p> class="post">${msg}</p> 
  6.       <p><em>Latest message above.</em></p> 
  7.     </div>`; 

一般來說,應該避免在JavaScript中創建大量HTML。同樣,這主要是為了做到數據層和行為層各司其職,在出錯時更容易定位問題所在。如果使用上面的代碼示例,那么如果動態插入的HTML格式不對,就會造成頁面布局出錯。但在這種情況下定位錯誤就更困難了。因為這時候通常首先會去找頁面中出錯的HTML源代碼,但又找不到,因為它是動態生成的。而且修改數據或頁面,還需要修改JavaScript,這說明兩層是緊密耦合的。

HTML渲染應該盡可能與JavaScript分開。在使用JavaScript插入數據時,應該盡可能不要插入標記。相應的標記可以包含并隱藏在頁面中,在需要的時候JavaScript可以直接用它來顯示,而不需要動態生成。另一個辦法是通過Ajax請求獲取要顯示的HTML,這樣也可以保證同一個渲染層(PHP、JSP、Ruby等)負責輸出標記,而不是把標記嵌在JavaScript中。

解耦HTML和JavaScript可以節省排錯時間,因為更容易定位錯誤來源。同樣解耦也有助于保證可維護性,對行為的修改只涉及JavaScript,而對標記的修改則只涉及要渲染的文件。

3.2 解耦CSS/JavaScript

Web應用的另一層是CSS,主要負責頁面的外觀。JavaScript和CSS是緊密相關的,它們都是建構在HTML之上的,因此也經常一起使用。與HTML和JavaScript的情況類似,CSS也可能與JavaScript產生強耦合。最常見的例子就是使用JavaScript修改個別樣式,比如:

  1. // CSS緊耦合到了JavaScript 
  2. element.style.color = "red"
  3. element.style.backgroundColor = "blue"

因為CSS負責頁面外觀,任何樣式的問題都應該通過CSS文件解決。可是,如果JavaScript直接修改個別樣式(比如顏色),就會增加一個排錯時要考慮甚至要修改的因素。結果是JavaScript某種程度上承擔了頁面顯示的任務,與CSS搞成了緊密耦合。如果將來有一天要修改樣式,那么CSS和JavaScript都需要修改。這對負責維護的開發者來說是一個惡夢。層與層的清晰解耦是必需的。

現代Web應用經常使用JavaScript改變樣式,因此雖然不太可能完全解耦CSS和JavaScript,但可以讓這種耦合變成更松散。這主要可以通過動態修改類名而不是樣式來實現,比如:

  1. // CSS與JavaScript松散耦合 
  2. element.className = "edit"

通過修改元素的CSS類名,可以把大部分樣式限制在CSS文件里。JavaScript只負責修改應用樣式的類名,而不直接影響元素的樣式。只要應用的類名沒錯,那么外觀的問題就只跟CSS有關,而跟JavaScript無關。

同樣,保證層與層之間的適當分離是至關重要的。顯示出問題就只應該去CSS里解決,行為出問題就只應該找JavaScript的問題。這些層之間的松散耦合可以提升整個應用的可維護性。

3.3 解耦應用邏輯/事件處理程序

每個Web應用中都會有大量事件處理程序在監聽各種事件。可是,其中很少有真正做到應用邏輯與事件處理程序分離的。來看下面的例子:

  1. function handleKeyPress(event) { 
  2.   if (event.keyCode == 13) { 
  3.     let target = event.target; 
  4.     let value = 5 * parseInt(target.value); 
  5.     if (value > 10) { 
  6.       document.getElementById("error-msg").style.display = "block"
  7.     } 
  8.   } 

這個事件處理程序除了處理事件,還包含了應用邏輯。這樣做的問題是雙重的。首先,除了事件沒有辦法觸發應用邏輯,結果造成調試困難。如果沒有發生預期的結果怎么辦?是因為沒有調用事件處理程序,還是因為應用邏輯有錯誤?其次,如果后續事件也會對應相同的應用邏輯,就會導致代碼重復,否則就要把它提取到一個函數中。無論如何,都會導致原本不必要的多余工作。

更好的做法是將應用邏輯與事件處理程序分開,各自只負責處理各自的事情。事件處理程序應該專注于event對象的相關信息,然后把這些信息傳給處理應用邏輯的某些方法。例如,前面的例子可以重寫成這樣:

  1. function validateValue(value) { 
  2.   value = 5 * parseInt(value); 
  3.   if (value > 10) { 
  4.     document.getElementById("error-msg").style.display = "block"
  5.   } 
  6.  
  7. function handleKeyPress(event) { 
  8.   if (event.keyCode == 13) { 
  9.     let target = event.target; 
  10.     validateValue(target.value); 
  11.   } 

這樣修改之后,應用邏輯跟事件處理程序就分開了。handleKeyPress()函數只負責檢查用戶是不是按下了回車鍵(event.keyCode等于13),如果是則取得事件目標,并把目標的值傳給validateValue()函數,由該函數處理應用邏輯。注意,validateValue()函數中不包含任何依賴事件處理程序的代碼。這個函數只負責接收一個值,然后可以對這個值做任何處理。

把應用邏輯從事件處理程序中分離出來有很多好處。首先,可以方便地修改觸發某個流程的事件。如果原來是通過鼠標單擊觸發流程,而現在又想增加鍵盤操作來觸發,那么修改起來也很簡單。其次,可以在不用添加事件的情況下測試代碼,這樣創建單元測試甚至與應用自動化整合都會更簡單。

以下是在解耦應用和業務邏輯時應該注意的幾點。

  • 不要把event對象傳給其他方法,而是只傳遞event對象中必要的數據。
  • 應用中每個可能的操作都應該無需事件處理程序就可以執行。
  • 事件處理程序應該處理事件,而把后續處理交給應用邏輯。

做到上述幾點能夠給任何代碼的可維護性帶來巨大的提升,同時也能為將來的測試和開發提供很多可能性。

4. 編碼慣例

編寫可維護的JavaScript不僅僅涉及代碼格式和規范,也涉及代碼做什么。大企業開發Web應用通常需要很多人協同工作。這時候就需要保證每個人的瀏覽器環境都有恒定不變的規則。為此,開發者應該遵守某些編碼慣例。

4.1 尊重對象所有權

JavaScript的動態天性意味著幾乎可以在任何時候修改任何東西。過去有人說,JavaScript中沒有什么是神圣不可侵犯的,因為不能把任何東西標記為最終結果或者恒定不變。但ECMAScript 5引入防篡改對象之后,情況不同了。當然,對象默認還是可以修改的。在其他語言中,在沒有源代碼的情況下對象和類都是不可修改的。JavaScript則允許在任何時候修改任何對象,因此就可能導致意外地覆蓋默認行為。既然這門語言沒有什么限制,那就需要開發者自己限制自己。

在企業開發中,可能最最重的編碼慣例就是尊重對象所有權,這意味著不要修改不屬于你的對象。簡單地講,如果你不負責創建和維護某個對象,包括它的構造函數或它的方法,就不應該對它進行任何修改。更具體一點說,就是:

  • 不要給實例或原型添加屬性
  • 不要給實例或原型添加方法
  • 不要重定義已有的方法

問題在于,開發者會假設瀏覽器環境以某種方式運行。修改了多個人使用的對象也就意味著會有錯誤發生。如果有人希望某個函數叫stopEvent(),用于取消某個事件的默認行為。然后,你把它給改了,除了取消事件的默認行為,又添加了其他事件處理程序。可想而知,問題肯定會接踵而至。別人還會認為這個函數只做最開始的那點事,由于對它后來添加的副作用并不知情,很可能會用錯或者造成損失。

以上規則不僅適用于自定義類型和對象,同樣適用于原生類型和對象,比如Object、String、document、window,等等。考慮到瀏覽器廠商也有可能會在不宣布的情況下以非預期方式修改這些對象,那么潛在的風險就更大了。

以前有一個流行的Prototype庫就發生過類似事件。當時,這個庫在document對象上實現了getElementsByClassName()方法,返回一個Array的實例,而這個實例上還增加了each()方法。jQuery的作者John Resig后來在自己的博客上分析了這個問題造成的影響。他在博客中(https://johnresig.com/blog/getelementsbyclassname-pre-prototype-16/)指出這個問題是由于瀏覽器也原生實現了相同的getElementsByClassName()方法造成的。但Prototype的同名方法返回的是Array而非NodeList,后者沒有each()方法。使用這個庫的開發者之前會寫這樣的代碼:

  1. document.getElementsByClassName("selected").each(Element.hide); 

盡管這樣寫在沒有原生實現getElementsByClassName()方法的瀏覽器里沒有問題,但在實現它的瀏覽器里就會出問題。因為兩個同名方法返回的結果不一樣。我們不能預見瀏覽器廠商將來會怎么修改原生對象,因此不管怎么修改它們都可能在將來某個時刻出現沖突時導致問題。

為此,最好的方法是永遠不要修改不屬于你的對象。只有你自己創建的才是你的對象,包括自定義類型和對象字面量。Array、document等這些都不是你的,因為在你的代碼執行之前它們已經存在了。可以這樣為對象添加新功能:

  • 創建包含想要功能的新對象,通過它與別人的對象交互。
  • 創建新自定義類型繼承本來想要修改的類型,給自定義類型添加新功能。

很多JavaScript庫目前都贊同這個開發理念,這樣無論瀏覽器怎樣改變都可以發展和適應。

4.2 不聲明全局變量

與尊重對象所有權密切相關的是盡可能不聲明全局變量和函數。同樣,這也關系到創建一致和可維護的腳本運行環境。最多可以創建一個全局變量,作為其他對象和函數的命名空間。來看下面的例子:

  1. // 兩個全局變量——不要! 
  2. var name = "Nicholas"
  3. function sayName() { 
  4.   console.log(name); 

以上代碼聲明了兩個全局變量:name和sayName()。可以像下面這樣把它們包含在一個對象中:

  1. // 一個全局變量——推薦 
  2. var MyApplication = { 
  3.   name: "Nicholas", 
  4.   sayName: function() { 
  5.     console.log(this.name); 
  6.   } 
  7. }; 

這個重寫后的版本只聲明了一個全局對象MyApplication。在這個對象內部,又包含name和sayName()。這樣可以避免之前版本的幾個問題。首先,變量name會覆蓋window.name屬性,而這可能會影響其他功能。其次,有助于分清功能都集中在哪里。調用MyApplication.sayName()從邏輯上就會暗示出現任何問題,都可以在MyApplication的代碼中找原因。

這樣一個全局對象可以擴展為命名空間的概念。命名空間涉及創建一個對象,然后通過這個對象來暴露能力。比如,Google Closure庫就利用了這樣的命名空間來組織其代碼。下面是幾個例子:

  • goog.string:用于操作字符串的方法。
  • goog.html.utils:與HTML相關的方法。
  • goog.i18n:與國際化(i18n)相關的方法。

對象goog就相當于一個容器,其他對象都包含在這里面。只要使用對象以這種方式來組織功能,就可以稱該對象為命名空間。整個Google Closure庫都構建在這個概念之上,能夠在同一個頁面上與其他JavaScript庫共存。

關于命名空間,最重要的是確定一個所有人都同意的全局對象名稱。這個名稱要足夠獨特,不可能與其他人的沖突。多數情況下,可以使用開發者所在的公司名,例如goog或Wrox。下面的例子演示了使用Wrox作為命名空間來組織功能:

  1. // 創建全局對象 
  2. var Wrox = {}; 
  3.  
  4. // 為本書(Professional JavaScript)創建命名空間 
  5. Wrox.ProJS = {}; 
  6.  
  7. // 添加本書用到的其他對象 
  8. Wrox.ProJS.EventUtil = { ... }; 
  9. Wrox.ProJS.CookieUtil = { ... }; 

在這個例子中,Wrox是全局變量,然后在它的下面又創建了命名空間。如果本書所有代碼都保存在Wrox.ProJS命名空間中,那么其他作者的代碼就可以使用自己的對象來保存。只要每個人都遵循這個模式,就不必擔心有人會覆蓋這里的EventUtil或CookieUtil,因為即使重名它們也只會出現在不同的命名空間中。比如下面的例子:

  1. // 為另一本書(Professional Ajax)創建命名空間 
  2. Wrox.ProAjax = {}; 
  3.  
  4. // 添加其他對象 
  5. Wrox.ProAjax.EventUtil = { ... }; 
  6. Wrox.ProAjax.CookieUtil = { ... }; 
  7.  
  8. // 可以照常使用ProJS下面的對象 
  9. Wrox.ProJS.EventUtil.addHandler( ... ); 
  10.  
  11. // 以及ProAjax下面的對象 
  12. Wrox.ProAjax.EventUtil.addHandler( ... ); 

雖然命名空間需要多寫一點代碼,但從可維護性角度看,這個代價還是非常值得的。命名空間可以確保代碼與頁面上的其他代碼互不干擾。

4.3 不要比較null

JavaScript不會自動做任何類型檢查,因此就需要開發者擔起這個責任。結果,很多JavaScript代碼都不會做類型檢查。最常見的類型檢查是看一個值是不是null。然而,與null進行比較的代碼太多了,其中很多都因為類型檢查不夠而頻繁引發錯誤。比如下面的例子:

  1. function sortArray(values) { 
  2.   if (values != null) { // 不要這樣比較! 
  3.     values.sort(comparator); 
  4.   } 

這個函數的目的是使用給定的比較函數對數組進行排序。為保證函數正常執行,values參數必須是數組。但是,if語句在這里只簡單地檢查了這個值不是null。實際上,字符串、數值還有其他很多值都可以通過這里的檢查,結果就會導致錯誤。

現實當中,單純比較null通常是不夠的。檢查值的類型就要真的檢查類型,而不是檢查它不能是什么。例如,在前面的代碼中,values參數應該是數組。為此,應該檢查它到底是不是數組,而不是檢查它不是null。可以像下面這樣重寫那個函數:

  1. function sortArray(values) { 
  2.   if (values instanceof Array) { // 推薦 
  3.     values.sort(comparator); 
  4.   } 

這個函數的這個版本可以過濾所有無效的值,根本不需要使用null。

  • 如果看到比較null的代碼,可以使用下列某種技術替換它。
  • 如果值應該是引用類型,使用instanceof操作符檢查其構造函數。
  • 如果值應該是原始類型,使用typeof檢查其類型。
  • 如果希望值是有特定方法名的對象,使用typeof操作符確保對象上存在給定名字的對象。

代碼中比較null的地方越少,就越容易明確類型檢查的目的,從而消除不必要的錯誤。

4.4 使用常量

依賴常量的目標是從應用邏輯中分離數據,以便修改數據時不會引發錯誤。顯示在用戶界面上的字符串就應該以這種方式提取出來,可以方便實現國際化。URL也應該這樣提取出來,因為隨著應用越來越復雜,URL也極有可能變化。基本上,像這種地方因為這種或那種原因將來需要修改時,可能就要找到某個函數,然后修改其中的代碼。而每次像這樣修改應用邏輯,都可能引入新錯誤。為此,可以把這些可能會修改的數據提取出來,放在單獨定義的常量中,以實現數據與邏輯分離。

關鍵在于把數據從使用它們的邏輯中分離出來。可以使用以下標準檢查哪些數據需要提取。

  • 重復出現的值。任何使用超過一次的值都應該提取到常量中。這樣可以消除一個值改了而另一個值沒改造成的錯誤。這里也包括CSS的類名。
  • 用戶界面字符串。任何會顯示給用戶的字符串都應該提取出來,以方便實現國際化。
  • URL:Web應用中資源的地址經常會發生變化,因此建議把所有URL集中放在一個地方管理。
  • 任何可能變化的值。任何時候,只要在代碼中使用字面值,就問問自己這個值將來有沒有可能會變。如果答案是有可能,那么就應該把它提取到常量中。

使用常量是企業級JavaScript的重要技術,因為它可以讓代碼更容易維護,同時可以讓代碼免受數據變化的影響。

責任編輯:趙寧寧 來源: 奇舞周刊
相關推薦

2022-06-06 00:43:35

系統架構設計

2024-10-30 08:08:45

2023-06-29 00:19:51

2023-10-16 09:30:06

Java代碼

2021-04-15 08:08:48

微前端Web開發

2023-04-28 14:54:57

架構開發React

2024-04-16 08:48:14

WPF開發MVVM庫Prism

2022-10-20 10:02:16

前端測試開發

2023-10-17 09:19:34

開發Java

2025-02-13 00:28:26

2021-03-11 14:33:28

Kubernetes開源容器

2023-01-27 14:53:03

2020-04-30 21:30:18

JavaScript前端技術

2024-04-18 08:39:57

依賴注入控制反轉WPF

2018-08-03 09:00:00

編程語言Python外部庫

2021-02-20 10:26:00

前端

2023-07-17 13:57:05

2017-08-24 17:05:06

2023-09-20 23:03:40

C++函數

2017-07-25 12:09:10

機器學習預測性維護模型
點贊
收藏

51CTO技術棧公眾號

999日本视频| 日韩一区二区电影在线| 日本一区视频在线播放| 国产精品福利电影| 欧美激情综合色综合啪啪| 亚洲国产精品嫩草影院久久| 欧美在线观看视频网站| 国产黄a三级三级三级av在线看 | 久久精品国产亚洲夜色av网站| 51精品视频一区二区三区| 久久网站免费视频| 成人影院在线观看| 国产夜色精品一区二区av| 91在线播放国产| 一级黄色av片| 激情久久久久久久| 精品国产一区二区三区久久久| 懂色av粉嫩av蜜乳av| 国产一区二区在线观| 色综合久久久久网| 免费人成在线观看视频播放| 69av亚洲| 久久精品欧美一区二区三区不卡| 97超碰人人看人人| 国产又大又长又粗| 日本视频免费一区| 青青青国产精品一区二区| 麻豆亚洲av成人无码久久精品| 日韩精品欧美| 国产一区二区三区四区福利| 国产精品对白刺激久久久| 999精品网站| 男女视频在线| 日韩电影免费观看高清完整版在线观看| 91视频.com| 国产精品v欧美精品v日韩精品| 97人妻精品一区二区三区软件 | 97色伦亚洲国产| 久草免费新视频| 欧美日韩一区自拍| 欧美成人三级视频网站| 永久免费看片视频教学| 成人看的羞羞网站| 在线视频国产日韩| 在哪里可以看毛片| 国产亚洲欧美日韩在线观看一区二区 | 欧美色图色综合| 55av亚洲| 精品久久久久久中文字幕一区奶水 | 最新版天堂资源在线| youjizz欧美| 精品国精品国产尤物美女| 久久aaaa片一区二区| 99re8精品视频在线观看| 欧美精品粉嫩高潮一区二区| 亚洲欧美自拍另类日韩| 成人国产在线| 91精品国产综合久久久久| 国产永久免费网站| av一级久久| 日韩欧美国产综合一区| 人妻互换一二三区激情视频| 国内精品国产成人国产三级粉色 | 成人欧美一区二区三区黑人| 国产又粗又猛又爽| 国产精品白丝jk黑袜喷水| 亚洲影视中文字幕| 亚洲老妇色熟女老太| av一区二区三区| 麻豆av一区二区三区| 成a人v在线播放| 国产精品成人免费精品自在线观看| 自拍偷拍99| hd国产人妖ts另类视频| 欧美性生交xxxxx久久久| 日韩中文字幕组| 青青国产精品| 精品不卡在线视频| 亚洲第一香蕉网| 日韩中文在线电影| 欧美高清在线播放| 亚洲不卡在线视频| 国产真实乱对白精彩久久| 国产乱码精品一区二区三区中文| 日韩av地址| 亚洲欧美日韩久久精品| 国产妇女馒头高清泬20p多| videos性欧美另类高清| 欧美精品精品一区| 噜噜噜在线视频| 日韩av有码| 国产69精品久久久| 伊人成年综合网| 国产精品99久久久久| 欧美另类高清视频在线| 国产秀色在线www免费观看| 亚洲国产一区视频| 91香蕉视频污版| 哺乳挤奶一区二区三区免费看| 亚洲欧美在线免费观看| 国产探花在线播放| 丝袜脚交一区二区| ts人妖另类在线| 91欧美在线视频| 图片区小说区区亚洲影院| 国产色视频在线播放| 高清欧美性猛交xxxx黑人猛| 色妞久久福利网| 久久免费激情视频| 国产成人鲁色资源国产91色综| 欧美重口乱码一区二区| 欧美aaaxxxx做受视频| 精品视频免费看| 国产白嫩美女无套久久| 欧美一区二区三区久久精品茉莉花| 欧美一级大片在线免费观看| 精品黑人一区二区三区在线观看| 国产欧美日韩麻豆91| 国产无限制自拍| 国产精品一区免费在线 | 日韩手机在线导航| 中文字幕第69页| 亚洲欧美大片| 国产伦精品一区二区三区视频孕妇| 嫩草在线视频| 欧美性色黄大片| 欧美黑人欧美精品刺激| 激情视频一区| 99在线首页视频| 里番在线观看网站| 欧美三级三级三级| 国产亚洲精品熟女国产成人| 9国产精品视频| 国产精品国模大尺度私拍| dy888亚洲精品一区二区三区| 欧美亚州韩日在线看免费版国语版| 国产又爽又黄无码无遮挡在线观看| 欧美日韩视频一区二区三区| 3d精品h动漫啪啪一区二区| 成人欧美在线| 91精品国产福利在线观看 | 色欲久久久天天天综合网| 亚洲激情自拍偷拍| 国模大尺度视频| **女人18毛片一区二区| 成人中文字幕+乱码+中文字幕| 日本不卡视频| 欧美顶级少妇做爰| 欧洲猛交xxxx乱大交3| 国产一区在线观看视频| 玖玖精品在线视频| 精品一区二区三区中文字幕视频| 久久综合久久美利坚合众国| 91麻豆国产在线| 国产精品传媒在线| 91网址在线观看精品| 欧美国产另类| 国产精品嫩草在线观看| 国产第一页在线| 亚洲白虎美女被爆操| 欧美日韩精品区| 久久嫩草精品久久久精品一| 男女啪啪网站视频| 999成人精品视频线3| 亚洲伊人久久大香线蕉av| 久久香蕉一区| 亚洲精品中文字幕av| 成年人晚上看的视频| 中文字幕第一区二区| 亚洲天堂一区二区在线观看| 亚洲视频日本| 久久精品五月婷婷| av成人免费看| 美女视频久久黄| 天天操天天操天天干| 欧洲在线/亚洲| 高h视频免费观看| av电影一区二区| av五月天在线| 国产精品多人| 日本不卡高清视频一区| 在线成人免费| 91精品国产高清久久久久久91| 成人18在线| 日韩一区二区三区免费观看| 国产午夜免费福利| 国产精品白丝在线| bl动漫在线观看| 麻豆91精品91久久久的内涵| 成人av在线不卡| 经典一区二区| 91免费版黄色| 欧美va在线| 欧美黑人xxx| 成人18在线| 亚洲国产美女久久久久| 超碰在线免费97| 亚洲超碰97人人做人人爱| 国产精品免费无码| 成a人片国产精品| 亚洲国产成人va在线观看麻豆| 在线免费观看欧美| 国产对白在线播放| 国产亚洲一区二区三区啪| 成人资源av| 精品久久在线| 欧美性三三影院| 精品国产一区二区亚洲人成毛片| 欧美精品久久天天躁| 日韩成人av免费| 一区二区国产在线观看| 亚洲狠狠丁香婷婷综合久久久| 午夜精品aaa| 777久久久精品一区二区三区 | 国产精品手机视频| 蜜桃无码一区二区三区| 国产精品永久久久久久久久久| 国产女人18水真多18精品一级做| 亚洲最大视频网| 久久99国产精品久久99果冻传媒| 成人在线观看你懂的| 亚洲最新av| 亚洲欧美国产一区二区| 蜜臀久久99精品久久一区二区| www.久久艹| 国产亚洲精品女人久久久久久| 免费av网站在线| 国模私拍视频在线播放| 精品99久久久久久| 一区二区三区www污污污网站| 日日夜夜亚洲精品| 欧美成a人片免费观看久久五月天| 亚洲成人一区二区| 182在线观看视频| 国产网站一区二区| 成年人网站免费在线观看| 丁香天五香天堂综合| 久久久久久久久久毛片| 美女尤物国产一区| 成人亚洲精品777777大片| 国产亚洲精品久久久久久无几年桃| 无码国产色欲xxxx视频| 亚洲免费观看高清完整版在线| 国产一二三四五区| 成人午夜激情视频| 美女伦理水蜜桃4| 国产成a人无v码亚洲福利| a级大片免费看| 国产精品一区二区三区四区| 亚洲天堂一区二区在线观看| jizz欧美| 久久精品这里热有精品| 尤物在线视频| 久久激情视频久久| 成年人黄视频在线观看| 久久国产色av| 久久久123| 8x海外华人永久免费日韩内陆视频 | 日韩av大片在线观看| 色综合久久99| 在线免费观看av片| 日韩一区二区在线免费观看| 性欧美一区二区三区| 精品福利在线导航| 久草在线青青草| 日韩少妇与小伙激情| 国产精品剧情一区二区在线观看| 欧美大片va欧美在线播放| 波多野结衣在线观看| 欧美一级视频在线观看| 91精品美女| 91av免费看| 麻豆成人入口| 婷婷精品国产一区二区三区日韩 | 9999久久久久| 欧美日韩国产综合视频在线| 日本一本不卡| 91成人综合网| 久久精品人人| 国产高清999| www.成人网.com| 国产精品情侣呻吟对白视频| 一二三区精品福利视频| 久久免费激情视频| 欧美二区在线观看| 日韩资源在线| 欧美尺度大的性做爰视频| 亚洲人体影院| 成人免费xxxxx在线观看| 97视频一区| 亚洲免费在线精品一区| 欧美成人69| 一道本视频在线观看| 盗摄精品av一区二区三区| 91中文字幕永久在线| 亚洲免费观看视频| 色屁屁影院www国产高清麻豆| 欧美一区二区视频网站| 男人的天堂在线视频| 欧美激情在线观看| 国产精品亲子伦av一区二区三区| 国产一区二区三区无遮挡| 99久久婷婷国产综合精品电影√| 97成人在线免费视频| 国产最新精品精品你懂的| 亚洲欧美在线不卡| 亚洲激情图片一区| 国产在线一级片| 精品亚洲永久免费精品| 免费网站在线观看人| 国产欧美日韩91| 国产亚洲精品美女久久久久久久久久| 99在线精品免费视频| 狠狠狠色丁香婷婷综合久久五月| 伊人网在线视频观看| 亚洲一区二区三区视频在线| 91女人18毛片水多国产| 在线观看中文字幕亚洲| 中国色在线日|韩| 国产伦理一区二区三区| 综合精品久久| 午夜xxxxx| 亚洲欧洲日韩女同| 99re热视频| 亚洲午夜av久久乱码| 美女的胸无遮挡在线观看| 国产精华一区| 欧美特黄一区| 亚洲av无码久久精品色欲| 国产精品理论片在线观看| 一级片在线免费播放| 日韩精品亚洲视频| 天堂在线中文网官网| 国产欧美一区二区三区另类精品| 欧美日韩亚洲国产精品| 亚洲精品mv在线观看| 国产精品久久久久婷婷二区次| 成人黄色片在线观看| 亚洲午夜未删减在线观看| 国产另类xxxxhd高清| 欧美日韩另类综合| 久久婷婷丁香| 亚洲黄色免费视频| 欧美特级限制片免费在线观看| 黄网站在线观看| 国产精品福利片| 日韩中文首页| 亚洲网中文字幕| 一区二区三区精品| 六月婷婷中文字幕| 97在线观看视频| 亚洲区小说区| 不卡av免费在线| 国产精品麻豆欧美日韩ww| 一区二区日韩视频| 九九热这里只有精品免费看| 99国产精品免费网站| 3d动漫一区二区三区| 久久你懂得1024| 一卡二卡三卡在线| 欧美另类高清videos| 日韩精品a在线观看91| 50路60路老熟妇啪啪| 中文字幕第一区二区| 精品人妻少妇AV无码专区| 国内精品小视频在线观看| 香蕉精品久久| 校园春色 亚洲色图| 一区二区视频在线看| 污视频软件在线观看| 国产999在线观看| 国产精品久久久乱弄| 一级少妇精品久久久久久久| 一道本成人在线| 菠萝菠萝蜜在线视频免费观看| 国产精品久久久久久久免费大片| 午夜亚洲福利在线老司机| 综合 欧美 亚洲日本| 欧美videossexotv100| 2022成人影院| 免费成人进口网站| 不卡的看片网站| 在线观看不卡的av| 午夜美女久久久久爽久久| 日韩欧美精品一区| 亚洲成a人无码| 欧美综合在线视频| 欧美日韩色网| 日韩精品一区二区三区丰满| 国产一区二区视频在线| 亚洲午夜18毛片在线看| 久久亚洲综合国产精品99麻豆精品福利| silk一区二区三区精品视频| 尤蜜粉嫩av国产一区二区三区| 亚洲国产欧美一区二区三区丁香婷| 成人影视在线播放| 国产精品一区二区三区在线| 美女国产一区二区| 色婷婷在线观看视频| 欧美精品一区三区|