最近閱讀了《編寫可維護的 JavaScript》,在這裏記錄一下讀書筆記。書中主要基於三個方向來說解怎麼增長代碼的可維護性:編程風格、編程實踐、自動化。javascript
筆記已加入到個人博客裏,歡迎 Star。html
縮進方式java
使用製表符(Tab 鍵)。git
命名方式github
變量名用名詞。編程
函數名用動詞開頭數組
null 對象的用法瀏覽器
// 好的寫法 var person = null; function getPerson(num){ if (num >5) { return new Person('Lily'); } else { // 好的寫法 return null; } } var person = new Person(); // 好的寫法 console.log(person === null);
var person; // 很差的寫法 console.log(person === null); function doSomeThing(arr1, arr2){ // 很差的寫法 if(arr1 === null){ console.log('arr1 參數沒有傳遞'); } }
使用註釋的通常原則是:讓代碼變得更清晰。咱們通常經過這幾點來註釋代碼:服務器
註釋的書寫規範:dom
能夠加一些註釋聲明。
var person = null; if (condition) { // 作一些事情 doSomeThing(); // 作一些事情 } /* * 這是建立一個對象 * 第二行 */ var p = new Person(); /** @method merge @param {Object} 被合併的對象 @return {Object} 一個新的對象 **/ function doSomeThing(obj) { return Object.assign(obj,{asd:123}); } // REVIEW: 有更好的寫法嗎? if(document.all){ }
在語句和表達式一章,書中主要是寫關於大括號對齊方式等,如下兩點讓我影響特別深入:
hasOwnProperty
。定義變量
提示
String 類型能夠調用 String 包裝器的方法,是由於語句的背後,JS 引擎建立了 String 類型的新實例,緊跟着就銷燬了,因此給 String 類型上添加屬性和方法是沒有用的。
在 WEB 開發中,用戶界面是由三個彼此隔離又相互做用的層定義的:HTML、CSS、JavaScript。因爲這三個部分是相互做用的,應該儘可能分開這幾個模塊,以加強代碼的可維護性。
將 JS 從 CSS 中抽離出來。
將 CSS 從 JS 中抽離出來。
將 JS 從 HTML 中抽離出來。
<div onclick="xxx"></div>
將 HTML 從 JS 中抽離出來。
div.innerHTML = '<h1>你好</h1>';
JS 可使用一下幾種方式來操做 HTML:
咱們都知道,在全局做用域下定義的變量和方法,都會掛載到 window 對象上,隨着對象越掛越多,項目也就愈來愈難以維護了。建立全局變量還會致使如下幾個問題:
代碼脆弱性
難以測試
單全局變量
引用命名空間概念:
AMD 模塊化
// AMD 模塊定義 define('module-name',['dep1','dep2'],function(dep1,dep2){});
RequireJS 增長了另外一個全局函數 require(),專門用來加載指定的依賴和執行回調函數。
require(['my-book'], function(books){ console.log(books); });
零全局變量
在編寫事件處理程序時,咱們應該遵照一下幾點:
實際應用場景是這樣的:
<button onclick="doSomeThing()">click me</button> <script> // 事件處理程序 function doSomeThing(e) { var clientX = e.clientX; // 不要將e 傳入應用邏輯中,只傳遞須要使用的字段 log(clientX); } // 應用邏輯 function log(text){ console.log(text); } </script>
推薦使用 typeof 來檢測原始類型的值。typeof 自己是一個表達式,因此推薦使用無括號的寫法。
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
typeof 是檢測 JS 檢測函數的最佳選擇。但 IE8 及其之前的瀏覽器對 DOM 上的方法實現方式有問題。
// IE 8 會存在問題 typeof document.getElementById // object
使用 Object.prototype.toString.call(value) === '[object Array]' 檢測數組效果很不錯,在 ES6 中能夠經過 Array.isArray 來實現。
檢測屬性使用如下兩個操做符:
在實際的項目中能夠遇到這種問題,原本只須要更改一些靜態數據,但因爲不當心改到了其餘業務代碼,致使部分業務代碼報錯。因此,把須要配置的靜態數據抽離出來是很是利於維護的。通常按照如下幾點將數據抽離出來:
咱們能夠將抽離出來的配置數據放在如下幾個地方:
咱們在開發項目時,遇到錯誤其實並不可怕,可怕的將這些錯誤帶到線上環境中去。爲此,在程序的一些關鍵地方,使用自定義錯誤,可讓咱們在上線前提早發現問題,避免出錯的影響變大。編寫自定義錯誤能夠遵照一下幾點:
function MyError(message){ this.message = message; } MyError.prototype = new Error();
在咱們編寫代碼的時候,會用到不少其餘對象,一些是存在於上下文做用域中、一些是存在於其餘庫裏等等,這些對象都不是咱們本身定義的。對於這些對象,咱們要作到徹底不去改動。其餘對象主要包括:
即便是目前項目中的對象,只要不是你寫的,也不該該隨便修改。
不新增方法
若是是必需要修改其餘對象,能夠經過繼承的方式來克隆一個以前的對象,而後再進行擴展。
Polyfills 的優勢是:若是瀏覽器提供原生實現,能夠很是輕鬆的移除他們。若是瀏覽器沒有實現,就使用現有的方法,巧妙地實現,實現過程可能會不精確。
一、user-agent 方式(能夠被篡改)。
二、使用特性檢測。爲特定瀏覽器的特性進行測試,並僅當特性存在時便可應用特性檢測。例如:
// 早期瀏覽器不支持 getElementById if(document.getElementById){ var dom = document.getElementById('xx') } else if(document.all){ var dom = document.all('xx') }
特性檢測的流程:
推斷是假設並不是事實。例如:這裏根據 getElementsByTagName 去推斷 getElementById,顯然是不合理的。
if(document.getElementsByTagName){ var dom = document.getElementById('xx') }
經過 document.all 判斷就是 IE 瀏覽器了,這是「自做聰明」的,由於其餘瀏覽器也可能存在 document.all。
if(document.all){ console.log('This is IE'); }
如下列舉了書中介紹的自動化配置過程,很實用,如今的項目均可以使用這些思想來配置持續集成。惋惜的是,如今看來書中的信息比較滯後(由於寫的早),不少介紹的庫已通過時了,這裏就不詳細介紹了。
自動化測試
組裝到一塊兒
這本書看着很快,三天時間就看完了,但書中的編碼規範,編程實踐部分仍是學到了很多東西。如今寫代碼會經常冒出幾個問題:註釋該怎麼寫?類型判斷要怎麼才最好?數據代碼是否抽離?