摘要:最近閱讀了編寫可維護(hù)的,在這里記錄一下讀書筆記。禁止使用,,,的字符串形式。避免使用級事件處理函數(shù)。讓事件處理程序成為接觸到對象的唯一函數(shù)。檢測函數(shù)是檢測檢測函數(shù)的最佳選擇。為特定瀏覽器的特性進(jìn)行測試,并僅當(dāng)特性存在時即可應(yīng)用特性檢測。
最近閱讀了《編寫可維護(hù)的 JavaScript》,在這里記錄一下讀書筆記。書中主要基于三個方向來講解怎么增加代碼的可維護(hù)性:編程風(fēng)格、編程實(shí)踐、自動化。
筆記已加入到我的博客里,歡迎 Star。
編程風(fēng)格
縮進(jìn)方式
使用空格(推薦)。
使用制表符(Tab 鍵)。
不同的操作系統(tǒng)對于制表符的解釋不一致,導(dǎo)致看起來不一致。
命名方式
變量名用名詞。
常量使用大寫單詞加下劃線 MAX_NUM。
函數(shù)名用動詞開頭
構(gòu)造函數(shù)用大駝峰寫法。
null 對象的用法
初始化一個變量。
和一個已經(jīng)初始化的變量做比較。
函數(shù)參數(shù)期望是對象時,用作參數(shù)傳入。
函數(shù)返回值是對象時,可以當(dāng)做返回值。
// 好的寫法 var person = null; function getPerson(num){ if (num >5) { return new Person("Lily"); } else { // 好的寫法 return null; } } var person = new Person(); // 好的寫法 console.log(person === null);
不要和非對象,或者未賦值變量做比較。
不要用來檢測函數(shù)參數(shù)是否傳入。
var person; // 不好的寫法 console.log(person === null); function doSomeThing(arr1, arr2){ // 不好的寫法 if(arr1 === null){ console.log("arr1 參數(shù)沒有傳遞"); } }編寫注釋
使用注釋的一般原則是:讓代碼變得更清晰。我們一般通過這幾點(diǎn)來注釋代碼:
難以理解的代碼。
可能被誤解的代碼。
瀏覽器 hack。
注釋的書寫規(guī)范:
注釋的上方需要一個空行。
單行注釋,如果在尾部注釋,需要加一個空格。
多行注釋中的每一行需對齊,最好也有一個星號。
可以加一些注釋聲明。
TODO 代碼未完成。
HACK 代碼走了一個捷徑,應(yīng)注明原因
FIXME 代碼有問題,應(yīng)盡快修復(fù)
REVIEW 代碼的改動需要評審
var person = null; if (condition) { // 做一些事情 doSomeThing(); // 做一些事情 } /* * 這是創(chuàng)建一個對象 * 第二行 */ var p = new Person(); /** @method merge @param {Object} 被合并的對象 @return {Object} 一個新的對象 **/ function doSomeThing(obj) { return Object.assign(obj,{asd:123}); } // REVIEW: 有更好的寫法嗎? if(document.all){ }語句和表達(dá)式
在語句和表達(dá)式一章,書中主要是寫關(guān)于大括號對齊方式等,以下兩點(diǎn)讓我影響特別深刻:
循環(huán)中盡可能避免使用 continue,使用條件判斷替代(可讀性更好)。
for in 循環(huán)只是用來遍歷對象的,不要用來遍歷數(shù)組。如果不需要遍歷原型鏈上的對象,可以使用 hasOwnProperty。
變量、函數(shù)和運(yùn)算符
定義變量
合并 var 語句,讓代碼更短。
函數(shù)內(nèi)部的變量定義應(yīng)作為函數(shù)內(nèi)的第一條語句。
for 語句初始化部分不應(yīng)該有變量聲明,應(yīng)提前到外面。
立即執(zhí)行的函數(shù)需要被一眼看出來,可以將函數(shù)用一堆圓括號包裹起來。
嚴(yán)格模式不要加在全局,只應(yīng)加在需要用到的函數(shù)作用域內(nèi),避免影響其他庫。
禁止使用 eval,new Function,setTimeOut,setInterval 的字符串形式。
三元運(yùn)算符僅僅用在賦值語句上,不要成為 if else 的替代品。
提示編程實(shí)踐
String 類型可以調(diào)用 String 包裝器的方法,是因?yàn)檎Z句的背后,JS 引擎創(chuàng)建了 String 類型的新實(shí)例,緊跟著就銷毀了,所以給 String 類型上添加屬性和方法是沒有用的。
在 WEB 開發(fā)中,用戶界面是由三個彼此隔離又相互作用的層定義的:HTML、CSS、JavaScript。由于這三個部分是相互作用的,應(yīng)該盡量分開這幾個模塊,以增強(qiáng)代碼的可維護(hù)性。
將 JS 從 CSS 中抽離出來。
避免使用 CSS 表達(dá)式。
將 CSS 從 JS 中抽離出來。
避免使用 JS 直接操作 dom.style 屬性。
應(yīng)該只需要操作 CSS 的 className 屬性。
將 JS 從 HTML 中抽離出來。
避免使用 DOM0 級事件處理函數(shù)。 例如:
使用自定義事件處理函數(shù)。
將 HTML 從 JS 中抽離出來。
避免 JS 使用寫死的 HTML 字符串,去 innerHTML 插入代碼。
div.innerHTML = "你好
";
JS 可以使用一下幾種方式來操作 HTML:
請求服務(wù)器,返回一段 HTML 文本,然后 innerHTML。
簡單客戶端模板,寫一個頁面不可見的模板,用變量的值去填充模板后,插入到頁面中來。
復(fù)雜客戶端模板,使用 Handlebars,創(chuàng)建模板,渲染數(shù)據(jù)。
避免創(chuàng)建全局變量我們都知道,在全局作用域下定義的變量和方法,都會掛載到 window 對象上,隨著對象越掛越多,項(xiàng)目也就越來越難以維護(hù)了。創(chuàng)建全局變量還會導(dǎo)致以下幾個問題:
命名沖突
代碼脆弱性
如果大量函數(shù)都引用了全局變量,而一旦某個地方不小心改變了值,所有使用的地方就完了。
難以測試
開發(fā)環(huán)境,測試環(huán)境,線上環(huán)境,都需要引入一套不同的全局變量,不方便維護(hù)。
解決全局變量方案
單全局變量
只使用一個對象定義在全局變量上,其他的對象都作為這個對象的屬性和方法。
引用命名空間概念:
調(diào)用 namespace() 來聲明開發(fā)者將要使用的命名空間,即:將對象掛載到哪個對象下,如果不存在,就創(chuàng)建一個對象。
AMD 模塊化
定義一個 define 方法,將模塊名,依賴,都傳進(jìn)去,在工廠方法里就能使用所依賴的模塊了。
// AMD 模塊定義 define("module-name",["dep1","dep2"],function(dep1,dep2){});
使用 RequireJS 更好地引入模塊。
RequireJS 增加了另一個全局函數(shù) require(),專門用來加載指定的依賴和執(zhí)行回調(diào)函數(shù)。
require(["my-book"], function(books){ console.log(books); });
零全局變量
如果你的腳本非常短,并且不需要和其他代碼產(chǎn)生交互,可以使用一個自執(zhí)行函數(shù)來實(shí)現(xiàn)模塊化。
事件處理在編寫事件處理程序時,我們應(yīng)該遵守一下幾點(diǎn):
隔離應(yīng)用邏輯。將應(yīng)用邏輯從所有的事件處理程序中抽離出來。
不要分發(fā)事件對象。只傳遞需要的數(shù)據(jù),給應(yīng)用邏輯就行了。
讓事件處理程序成為接觸到 Event 對象的唯一函數(shù)。其他需要用到的,就從事件處理程序中傳遞。
實(shí)際應(yīng)用場景是這樣的:
類型檢測 檢測原始類型
推薦使用 typeof 來檢測原始類型的值。typeof 本身是一個表達(dá)式,所以推薦使用無括號的寫法。
檢測自定義類JS 檢測自定義類時,最好的做法是使用 instanceof,這也是唯一的方法。
function Person(){} var p = new Person(): console.log(p instanceof Person);
instanceof 也可以檢測引用對象的值。但可能會檢測到原型對象上。
var now = new Date(); console.log(now instanceof Date); // true console.log(now instanceof Object); // true檢測函數(shù)
typeof 是檢測 JS 檢測函數(shù)的最佳選擇。但 IE8 及其以前的瀏覽器對 DOM 上的方法實(shí)現(xiàn)方式有問題。
// IE 8 會存在問題 typeof document.getElementById // object檢測數(shù)組
使用 Object.prototype.toString.call(value) === "[object Array]" 檢測數(shù)組效果很不錯,在 ES6 中可以通過 Array.isArray 來實(shí)現(xiàn)。
檢測屬性檢測屬性使用以下兩個操作符:
in 運(yùn)算符(會檢測原型鏈上的屬性)
hasOwnProperty
將配置數(shù)據(jù)從代碼中分離出來在實(shí)際的項(xiàng)目中可以遇到這種問題,本來只需要更改一些靜態(tài)數(shù)據(jù),但由于不小心改到了其他業(yè)務(wù)代碼,導(dǎo)致部分業(yè)務(wù)代碼報錯。所以,把需要配置的靜態(tài)數(shù)據(jù)抽離出來是非常利于維護(hù)的。一般按照以下幾點(diǎn)將數(shù)據(jù)抽離出來:
URL
展示給用戶的字符串
重復(fù)的值
設(shè)置信息
任何可能發(fā)生變更的值
我們可以將抽離出來的配置數(shù)據(jù)放在以下幾個地方:
抽離數(shù)據(jù)到一個 JSON 文件中。(通過請求去獲取)
抽離封裝到一個 JSONP 文件中。(通過 script 標(biāo)簽獲取)
使用純 javascript。(直接讀取)
拋出自定義錯誤我們在開發(fā)項(xiàng)目時,遇到錯誤其實(shí)并不可怕,可怕的將這些錯誤帶到線上環(huán)境中去。為此,在程序的一些關(guān)鍵地方,使用自定義錯誤,可以讓我們在上線前提前發(fā)現(xiàn)問題,避免出錯的影響變大。編寫自定義錯誤可以遵守一下幾點(diǎn):
總是在錯誤信息中包含函數(shù)名稱,以及函數(shù)失敗的原因。
只在該拋出錯誤的地方拋出錯誤,不必要過度的進(jìn)行錯誤預(yù)判,拋出錯誤。
如果使用 try catch ,catch 里不能為空,應(yīng)該對錯誤做一些處理。
對于自定義錯誤,最好是繼承 Error 錯誤類型,瀏覽器會給 Error 對象附加一些額外的信息。
function MyError(message){ this.message = message; } MyError.prototype = new Error();不是你的對象不要動
在我們編寫代碼的時候,會用到很多其他對象,一些是存在于上下文作用域中、一些是存在于其他庫里等等,這些對象都不是我們自己定義的。對于這些對象,我們要做到完全不去改動。其他對象主要包括:
JS 原生對象
DOM 對象
瀏覽器對象模型,BOM 對象
類庫的對象
即使是目前項(xiàng)目中的對象,只要不是你寫的,也不應(yīng)該隨便修改。
不要覆蓋方法
不新增方法
例如:Prototype 庫,是在源生 JS 上擴(kuò)展一些方法,但擴(kuò)展的方法可能以后被新的規(guī)范所使用,Prototype 庫不得不立即修改以支持新的規(guī)范。
不刪除方法
如果是必須要修改其他對象,可以通過繼承的方式來克隆一個之前的對象,然后再進(jìn)行擴(kuò)展。
基于對象的繼承(常規(guī)的繼承)
基于類型的繼承(如繼承 Error 類型)
關(guān)于 PolyfillPolyfills 的優(yōu)點(diǎn)是:如果瀏覽器提供原生實(shí)現(xiàn),可以非常輕松的移除他們。如果瀏覽器沒有實(shí)現(xiàn),就使用現(xiàn)有的方法,巧妙地實(shí)現(xiàn),實(shí)現(xiàn)過程可能會不精確。
為了防止對象修改防止擴(kuò)展 Object.preventExtensions() 不可擴(kuò)展
密封對象 Object.seal() 不能刪除已存在屬性,不可擴(kuò)展
凍結(jié)對象 Object.freeze() 不能修改已存在的屬性,不能刪除已存在屬性,不可擴(kuò)展
瀏覽器嗅探1、user-agent 方式(可以被篡改)。
2、使用特性檢測。為特定瀏覽器的特性進(jìn)行測試,并僅當(dāng)特性存在時即可應(yīng)用特性檢測。例如:
// 早期瀏覽器不支持 getElementById if(document.getElementById){ var dom = document.getElementById("xx") } else if(document.all){ var dom = document.all("xx") }
特性檢測的流程:
探測標(biāo)準(zhǔn)的方法。
探測不同瀏覽器的特定方法。
都不存在時,提供一個合乎邏輯的備用方法。
避免特性推斷推斷是假設(shè)并非事實(shí)。例如:這里根據(jù) getElementsByTagName 去推斷 getElementById,顯然是不合理的。
if(document.getElementsByTagName){ var dom = document.getElementById("xx") }避免瀏覽器推斷
通過 document.all 判斷就是 IE 瀏覽器了,這是“自作聰明”的,因?yàn)槠渌麨g覽器也可能存在 document.all。
if(document.all){ console.log("This is IE"); }自動化
以下列舉了書中介紹的自動化配置過程,很實(shí)用,現(xiàn)在的項(xiàng)目都可以使用這些思想來配置持續(xù)集成。可惜的是,現(xiàn)在看來書中的信息比較滯后(因?yàn)閷懙脑纾芏嘟榻B的庫已經(jīng)過時了,這里就不詳細(xì)介紹了。
ant 構(gòu)建工具
校驗(yàn)語法錯誤
文件合并和加工
文件精簡和壓縮
文檔化
自動化測試
PhantomJS
組裝到一起
jekins
總結(jié)這本書看著很快,三天時間就看完了,但書中的編碼規(guī)范,編程實(shí)踐部分還是學(xué)到了不少東西。現(xiàn)在寫代碼會常常冒出幾個問題:注釋該怎么寫?類型判斷要怎么才最好?數(shù)據(jù)代碼是否抽離?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/103016.html
摘要:盡管在類庫中,可能會經(jīng)常用到通常和操作有關(guān),另外三種用法即使也非常罕見。一個通用的原則是,禁止使用,并且只在別無他法時使用,。和也是可以使用的,但不要用字符串形式而要用函數(shù) 再javascript中,eval()的參數(shù)是一個字符串,eval()會將傳入的字符串當(dāng)做代碼來執(zhí)行,開發(fā)者可以通過這個函數(shù)來載入外部的javascript代碼,活著隨機(jī)生成Javascript代碼并執(zhí)行它,比如:...
摘要:解耦優(yōu)勢代碼復(fù)用,單元測試。常用比較誤區(qū)可同時判斷,可用來判斷對象屬性是否存在。使用作判斷無法進(jìn)行充分的類型檢查。文件中應(yīng)用常量參考文檔高級程序設(shè)計(jì)作者以樂之名本文原創(chuàng),有不當(dāng)?shù)牡胤綒g迎指出。 showImg(https://segmentfault.com/img/bVburXw?w=500&h=400); 編寫可維護(hù)性代碼 可維護(hù)的代碼遵循原則: 可理解性 (方便他人理解) 直觀...
摘要:特指度度量的是選擇器識別元素的精確性。為中的各個變量賦予相應(yīng)的數(shù)值,就能得到特指度。為類選擇器屬性選擇器和偽類的數(shù)量。該文件包含選項(xiàng)卡組的樣式。易于混淆的屬性,應(yīng)用注釋予以說明。屬性按照字母順序排列。屬性值為時,省略單位。 1、什么是優(yōu)秀的架構(gòu) (1)優(yōu)秀的架構(gòu)是可預(yù)測的(2)優(yōu)秀的架構(gòu)是可擴(kuò)展的(3)優(yōu)秀的架構(gòu)可提升代碼復(fù)用性(4)優(yōu)秀的架構(gòu)可擴(kuò)展(5)優(yōu)秀的架構(gòu)可維護(hù)什么時候可以重...
摘要:第條盡量少使用全局對象避免聲明全局變量盡量聲明局部變量避免對全局變量增加屬性第條始終聲明局部變量第條避免使用語句第條熟練使用閉包的函數(shù)值包含了比調(diào)用他們時執(zhí)行所需要的代碼還要更多的信息。那些在其所涵蓋的作用域內(nèi)跟蹤變量的函數(shù)稱為閉包。 書還沒看完。一遍看,一遍寫讀書筆記。 這本書的序是JavaScript之父Brendan Eich寫的,作者是JavaScript標(biāo)準(zhǔn)化委員會專家。可想...
摘要:異步請求線程在在連接后是通過瀏覽器新開一個線程請求將檢測到狀態(tài)變更時,如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個回調(diào)再放入事件循環(huán)隊(duì)列中。 基礎(chǔ):瀏覽器 -- 多進(jìn)程,每個tab頁獨(dú)立一個瀏覽器渲染進(jìn)程(瀏覽器內(nèi)核) 每個瀏覽器渲染進(jìn)程是多線程的,主要包括:GUI渲染線程 JS引擎線程 也稱為JS內(nèi)核,負(fù)責(zé)處理Javascript腳本程序。(例如V8引擎) JS引擎線程負(fù)...
閱讀 2825·2021-11-25 09:43
閱讀 978·2021-10-11 10:57
閱讀 2477·2020-12-03 17:20
閱讀 3716·2019-08-30 14:05
閱讀 2421·2019-08-29 14:00
閱讀 1990·2019-08-29 12:37
閱讀 1660·2019-08-26 11:34
閱讀 3201·2019-08-26 10:27