[筆記]最佳實踐

賴嘉豪發表於2018-11-12

最佳實踐將分為三大方面講述:1.可維護性、2.效能、3.部署

參考《JavaScript高階程式設計》總結出以下內容:

1.可維護性

1.1什麼是可維護的程式碼?

可維護的程式碼遵循以下特點:

  1. 可理解性:其他人可以接手程式碼並理解它的意圖和一般途徑,而無需開發人員的完整解釋。
  2. 直觀性:程式碼中的東西一看就能明白,不管其操作過程多麼複雜。
  3. 可適應性:程式碼以一種資料上的變化不要求完全重寫的方法撰寫。
  4. 可擴充性:在程式碼架構上已考慮到在未來允許對核心功能進行擴充套件。
  5. 可除錯性:當有地方出錯時,程式碼可以給予你足夠的資訊來儘可能直接的確定問題所在。

1.2 程式碼約定

1.可讀性:可維護的前提是必須可讀,所以可讀性是很重要的,主要兩方面改善可讀性:縮排,註釋。

一般而言以下地方需要進行註釋:

1、函式和方法

2、大段程式碼

3、複雜的演算法

4、Hack

2.變數和函式命名

適當給變數和函式起名字對於增加程式碼可理解性和可維護性是非常重要的。

命名規則如下:

  • 變數名應為名詞如car或person
  • 函式名應該以動次開始,如getName()。返回布林型別值的函式一般以is開頭,如isEnable()。
  • 變數和函式都應使用合乎邏輯的名字,不要擔心長度。長度問題可以通過後處理和壓縮來緩解。

3.變數型別透明

JavaScript中變數型別是鬆散型別的,所以很容易就忘記變數所應包含的資料型別。合適的命名方式可以一定程度上緩解這個問題,但放到所有的情況下看,還不夠。有三種表示變數資料型別的方式。

第一種方式是初始化。當定義了一個變數後,他應該被初始化為一個值,來暗示他將來應該如何應用,例如:

var found = false;          //布林型
var count = -1;             //數字
var name  = '';             //字串
var person= null;           //物件複製程式碼

初始化為一個特定的資料型別可以很好的指明變數的型別,但缺點是他無法用於函式宣告中的引數。

第二種方法是使用匈牙利標記法來指定變數型別。例如:

var bFound;     //布林型
var iCount;     //整數
var sName;      //字串
var oPerson;    //物件複製程式碼

最後一種方法是使用型別註釋。型別註釋放在變數名右邊。如下所示:

var found /*:Boolean*/ = false;
var count /*:int*/     = 10;
var name  /*:String*/  = 'nicholas';
var person /*:Object*/ = null;複製程式碼

缺點是不能用多行註釋一次註釋大塊的程式碼。


1.3 鬆散耦合

只要應用的某個部分過分依賴於另一部分,程式碼就是耦合過緊,男與維護。典型的問題如:物件直接引用另一個物件,並且當修改其中一個的同時需要修改另外一個。緊密耦合的軟體難於維護並且需要經常重寫。

1.解耦HTML/JavaScript

儘量避免的緊密耦合情況:

1、直接寫在HTML中的JavaScript

2、使用事件處理程式屬性值的緊密耦合的HTML/javascript

3、在JavaScript中建立大量HTML。

理想的情況是,HTL和JavaScript應該完全分離,並且通過外部檔案和使用DOM附加行為來包含JavaScript。


2.解耦CSS/JavaScript

現代Web開發免不了要用JavaScript改變某些樣式,但是將來如果需要更改樣式表,CSS和JavaScript檔案可能都需要更改。這會對開發人員造成心理陰影...所以在這兩個層次之間必須有清晰的劃分。

但也是有解決方法的:通過更改樣式類而非特定樣式。


3.解耦應用邏輯/事件處理程式


1.4 程式設計實踐

1.尊重物件所有權

意思是你不能修改不屬於你的物件。更具體的說:

  • 不要為例項或原型新增屬性;
  • 不要為例項或原型新增方法;
  • 不要重定義已存在的方法。

只要物件不是自己建立的,就永遠不去修改,明顯Array、document這些物件都不是你的,它們在你的程式碼執行前就存在了。但是依然可以通過以下方式為物件建立新的功能:

  • 建立包含所需功能的新物件,並用它與相關物件進行互動;
  • 建立自定義型別,繼承需要進行修改的型別,然後可以為自定義型別新增額外功能。


2.避免全域性變數

3.避免與null進行比較

4.使用常量

儘管JavaScript沒有常量的正是概念,但它還是很有用的。這種將資料從應用邏輯分離出來的思想,可以在不冒引入錯誤的風險的同時,就改變資料。請看以下例子:

function validata(value){
    if(!value){
        alert('Invalid value!');
        location.href = '/errors/invalid.php';
    ]
}複製程式碼

這個函式中有兩段資料:要顯示給使用者的資訊以及URL。顯示在使用者介面上的字串應該以允許進行語言國際化的方式抽取出來。URL也應該被抽取出來,因為它們有隨著應用成長而改變的傾向。 基本上,有著可能由於這樣那樣原因會變化的這些資料,那麼都會需要找到函式並在其中修改程式碼。而每次修改應用邏輯的程式碼,都可能會引入錯誤。可以通過將資料抽取出來變成單獨定義的常量的方式,將應用邏輯與資料修改隔離開來。例如:

var Constants = {
    INVALID_VALUE_MSG: 'Invalid value!',
    INVALID_VALUE_URL: '/errors/invalid.php'
};

function validata(value){
    if (!value){
        alert(Constants.INVALID_VALUE_MSG);
        location.href = Constants.INVALID_VALUE_URL;
    }
};複製程式碼

在這段重寫過的程式碼中,訊息和URL都被定義於Constants物件中,然後函式引用這些值。這些設定允許資料在無需使用它的函式的情況下進行變更。Constants物件甚至可以在完全獨立的檔案中定義,同時該檔案可以由包含正確值的其他過程根據國際化設定來生成。

關鍵在於將資料和使用它的邏輯進行分離。要注意的值的型別如下所示。

重複值:任何在多出用到的值都應該抽取為一個常量,這就限制了當一個值變了而另一個沒變的時候會造成的錯誤。這也包含了CSS類名。

使用者介面字串:任何使用者顯示給使用者的字串,都應被抽取出來以方便國際化。

URLs:在Web應用中,資源位置很容易變更,所以推薦一個公共地方存放所有的URL。

任意可能會更改的值:每當你在用到字面量值的時候,你都要問一下自己這個值在未來是不是會變化。如果答案是‘是’,那麼這個值就應該被提取出來作為一個常量。

對於企業級的JavaScript開發而言,使用常量是非常重要的技巧,因為他能讓程式碼更容易維護,並且在資料更改的同時保護程式碼。


2.效能

2.1 注意作用域

只要能減少化肥在作用域鏈上的事件,就能增加指令碼的整體效能。

1.避免全域性查詢

2.避免with語句


2.2 選擇正確方法

1.避免不必要的屬性查詢。

屬性查詢越多,執行時間就越長。

一般來講,只要能減少演算法的複雜度,就要儘可能減少。儘可能多地使用區域性變數將屬性查詢替換為值查詢。

2.優化迴圈

迴圈的基本優化步驟如下所示:

  1. 減值迭代:大多數迴圈使用一個從0開始、增加到某個特定值的迭代器。在很多情況ixa、從最大值開始,在迴圈中不斷減值的迭代器更加高效。
  2. 簡化終止條件:由於每次迴圈過程都會計算終止條件,所以必須保證它儘可能快。也就是說避免屬性查詢或其他O(n)的操作。
  3. 簡化迴圈體:迴圈體是執行最多的,所以要確保其被最大限度的有話啊。確保沒有某些可以被很容易移出迴圈的密集計算。
  4. 使用後測試迴圈:do-while

3.展開迴圈

當迴圈的次數是確定的,消除迴圈並使用多次函式呼叫往往更快。

針對大資料集使用展開迴圈可以節省很多時間,但對於小資料集,額外的開銷則可能得不償失。它是要花更多的程式碼來完成同樣的任務,如果處理的不是大資料集,一般來說並不值得。

4.避免雙重解釋

5.效能的其他注意事項

  • 原生方法較快:只要有可能,使用原生方法而不是自己用JavaScript重寫一個。
  • switch語句較快:如果有一系列複雜的if-else語句,可以轉換成單個switch語句則可以得到更快的程式碼。 還可以通過將case語句按照最可能的到最不可能的順序進行組織,來進一步優化switch語句。
  • 位運算子較快


2.3 最小化語句數

JavaScript程式碼中的語句數量也影響所執行的操作的速度。完成多個操作的單個語句要比完成單個操作的多個語句快。所以就要找出可以組合在一起的語句,以減少指令碼整體的執行時間。

1.多個變數宣告

多個變數的宣告儘量用一個語句。例如

//4個語句-很浪費
var count = 5;
var color = 'blue';
var values = [1,2,3];
var now = new Date();複製程式碼

重寫如下:

var count = 5,
    color = 'blue',
    values = [1,2,3],
    now = new Date();
複製程式碼

2.插入迭代值

當使用迭代值的時候,儘可能合併語句。請看程式碼:

var name = values[i];
i++;複製程式碼

優化後

var name = values[i++];複製程式碼

3.使用陣列和物件字面量(不用建構函式)

使用建構函式總是要用到更多的語句來插入元素或者定義屬性,而字面量可以將這些操作在一個語句中完成。例如:

//用4個語句建立和初始化陣列 - 浪費
var values = new Array();
values[0] = 123;
values[1] = 456;
values[2] = 789;

//用4個語句建立和初始化物件 - 浪費
var person = new Object*(;
person.name = 'nicholas';
person.age = 29;
person.sayName = function(){
    alert(this.name);
};複製程式碼

重寫:

//只用一條語句建立和初始化資料
var values = [123,456,789];

//只用一條語句建立和初始化物件
var person = {
    name : 'nicholas',
    age : 29,
    sayName : function(){
        alert(this.name);
    }
};複製程式碼

只要有可能,儘量使用陣列和物件的字面量表達方式來消除不要的語句。


2.4 優化DOM互動

在JavaScript的各方面中,DOM毫無疑問是最慢的一部分。

所以優化DOM互動是極其重要的,下面是關於DOM優化的總結:

1.最小化現場更新:儘量一次性把DOM元素新增成功,新增的操作(現場更新)越少越好。

2.使用innerHTML:innerHTML方法會在後臺建立一個HTML解析器,然後使用內部的DOM呼叫來建立DOM,而非基於JavaScript的DOM呼叫。由於內部方法是編譯好的而非解釋執行的,所以執行快得多。

3.使用事件代理

4.注意HTMLCollection:最小化訪問HTMLCollection的次數可以極大地改進指令碼的效能。例如:

var images = document.getElementsByTagName('img'),
    i,len;
for(i=0,len=images.length;i<len;i++){
    //處理
}複製程式碼

這裡的關鍵在於長度length存入了len變數,而不是每次都去訪問HTMLCollection的length屬性,當在迴圈中使用HTMLCollection的時候,下一步應該是獲取要使用的專案的引用,如下所示,一邊避免在迴圈體內多次呼叫HTMLCollection

var images = document.getElementsByTagName('img'),
    image,
    i,len;
for(i=0,len=images,length;i<len;i++){
    image = images[i];
    //處理
}複製程式碼

這段程式碼新增了image變數,儲存了當前的影象,這之後在迴圈內疚沒有理由在訪問images的HTMLCollection了。

發生以下情況時會返回HTMLCollection物件:

  1. 進行了對getElementsByTagName()的呼叫;
  2. 獲取了元素的childNodes屬性;
  3. 獲取了元素的attributes屬性;
  4. 訪問了特殊的集合,如document.forms/document.images等。



以上。



相關文章