在掌握如何編寫JAVAScript代碼之后,那么就進階到實踐——如何真正地解決問題。我們需要更改JS代碼使其更簡單、更易于閱讀,因為這樣的程序更易于團隊成員之間緊密協作。
今天,我們將介紹15個最佳實踐技巧,可幫助簡化JavaScript代碼,易于其他開發人員理解,也使程序更具可讀性和可維護性。
1. 在頂部聲明并初始化變量
沒有什么比延遲聲明更能破壞可讀性的了。正如在開始工作之前準備好所有工具可以幫助簡化工作,在進入函數的細節之前聲明所有變量也可以讓程序更簡單。這也方便了我們以后調整變量名稱或值。
至于變量,最佳做法是在創建時初始化變量,以便你和你的團隊都可以確定沒有undefined的變量。
<script>
var x = 5;
</script>
2. 構建模塊化、專業化的函數
為了效率和可讀性,單個函數走天下是不可行的。所以我們在設計函數時,應該秉持著一個任務一個函數的原則。函數命名也應當匹配任務。
這樣做是不是更方便其他人閱讀代碼了呢?因為只處理一項任務,自然而然函數就會更簡單。甚至以后如果有需要,你和你的團隊還可以將此函數應用到其他程序。
請看下面的示例,改進后的代碼只看函數名和變量名,就可以清楚地知道任務目的。
function table (columns, rows, item){
creates table and searches it for the passed item
}
// compared to
function createTable (columns, rows){
//creates table
}
function searchTable (table.length, item) {
//searches table for the passed item
}
3. 識別并刪除重復代碼
有時,代碼中不可避免地會出現重復的代碼行。在這種情況下,應將重復的代碼改寫為函數,并在以前所有使用過這些代碼的地方改為調用函數。
這不但減少了視覺混亂,還有助于以后的調試,因為這樣一來團隊只需要查看函數,而不必一一檢查多處代碼。
<script>
var x = 5;
var y = 6;
var x = x*2
var y = y*2
</script>
<script>
var x = 5;
var y = 6;
function double (value){
return value*2;
}
double (x);
double(y);
</script>
4. 多注釋代碼
注釋是總結代碼片段目的的好方法,可以節省其他開發人員靠自己去確定代碼所需的時間。
如果代碼未完成注釋描述應完成的任務,還能及時捕獲可能的錯誤。一般來說,最好每個函數都有一條注釋。
不確定應不應該寫注釋?那就寫吧!如果太過雜亂,大不了以后刪除罷了。
//declares and initializes var x
<script>
var x = 5;
</script>
5. 謹防過度使用遞歸
注意:遞歸函數不要嵌套太多層。雖然說多層嵌套能一次解決許多問題,但我們很難一目了然。
為避免困惑,盡可能在不產生大量運行時成本的前提下,解放嵌套的遞歸函數。如果你有3+層的嵌套函數,那么你的同事可能很難跟上你的思路。
function1 (a,b){
function2{
function3{
//this is too hard to follow and can likely be solved another way
}
}
}
</script>
6. 高效使用DOM操作
訪問DOM對于充分利用程序至關重要,但反復這樣做會導致視覺混亂并會減慢程序速度。
因此,我們最好訪問一次并進行緩存,以供稍后在變量中使用。然后有需要的話,直接訪問變量而不是訪問DOM。這個過程在視覺上更干凈、更高效。
注意:最佳做法是使用$符號標記DOM引用。
function accountInfo(){
var emAIl = $("#accounts").find(".email").val();
var accountNumber = $("#accounts").find(".accountNumber").val();
}
// Contents cached to variable "accounts"
function accountInfo(){ var $accounts = $("#accounts");
var name = $accounts.find(".email").val();
var age = $accounts.find(".accountNumber").val();
}
7. 不惜一切代價避免全局變量
在JavaScript中,變量具有或全局或局部的作用域。作用域決定了在代碼何處定義和訪問變量。我們可以在程序中的任何位置,甚至函數之外定義全局變量。而局部變量僅用于定義的函數中。
如果存在同名的局部變量和全局變量,那么JavaScript將優先考慮局部變量并忽略全局變量。我們應避免使用全局變量,因為全局變量可能會意外覆蓋窗口變量,從而導致錯誤。
此外,過多的全局變量會減慢程序速度,因為在窗口關閉之前不會刪除全局變量,而局部變量會在函數完成后刪除。
<html>
<script>
var myVar = "my global variable"; // This variable is declared as global
function localVariable( ) {
var myVar = "my local variable"; // This is a locally declared variable
</script>
</body>
</html>
8. 使用速記符號(對象文字)
在JavaScript中設計對象或數組時,可以通過選擇速記符號來節省空間。實現方式是在聲明期間而不是之后設置對象或數組的屬性。
這樣做,我們就不必確定在每一行上設置了哪個對象或數組,從而使這部分代碼更易于閱讀。雖然是一個很小的變化,但隨著對象和數組逐漸變得復雜,絕對可以為你的團隊節省很多時間。
例如創建一個對象
普通寫法:
var computer = new Object();
computer.caseColor = 'black';
computer.brand = 'Dell';
computer.value = 1200;
computer.onSale = true;
速記寫法:
var computer = {
caseColor: 'black';
brand: 'Dell';
value: 1200;
onSale: true;
}
速記數組:
var computerBrands = [
'Dell',
'Apple',
'Lenovo',
'HP',
'Toshiba',
'Sony'
];
9. 使用嚴格模式捕獲靜默錯誤
與其他編程語言(如C++和Java)相比,JavaScript是一種語法非常寬松的語言。雖然這種寬大處理有助于在不引發錯誤的情況下運行代碼,但可能會導致隱形的錯誤。所以我們需要解決隱形的靜默錯誤,否則可能會導致意料之外的行為。
解決方案就是嚴格模式。包括兩項主要更改:
- 以前可以通過編譯器的靜默錯誤現在會引發錯誤
- 修復了阻止JavaScript優化代碼的錯誤
- JavaScript Strict Code程序通常比非嚴格模式下的程序運行得更快。
或者在腳本部分的頂部,或者在所需功能之前(部分嚴格),添加'use strict';即可進入嚴格模式。
10. 設置默認值
創建對象時,可以為對象的部分或全部屬性設置默認值。這樣做不僅可確保每個屬性的值都不是undefined,而且還聲明了屬性所需的數據類型。此外,通過不為某些屬性設置默認值,還可以向團隊傳達對象正常運行不需要這些值的意思。
function logProperty({
address = '111 11th Street, 11111',
unit, //optional
landlord = 'Sara',
tenant = 'Raj',
rent = 500,
})
上面的代碼中,unit屬性可選,但其他四個屬性(預期的數據類型)都必須有默認值。為此,unit留空。
11. 使用模板字面量組合字符串
組合字符串可太麻煩了,尤其是在組合字符串和變量時。我們可以使用模板字面量(用反引號標記),簡化組合過程,因為模板字面量同時接受字符串和變量。
function greet(name) {
return `Hi, ${name}`; //template literal
}
console.log(greet('Leo'));
注意,通過使用模板字面量,我們可以根據傳遞的名稱、組合字符串Hi和變量name傳遞的值來記錄對用戶的問候語。因此,此代碼打印:Hi, Leo
12. 使用includes解決存在性測試
測試數組中值是否存在是一個常見問題。值得慶幸的是,JavaScript有一個特殊的數組方法include()——如果數組包含搜索值,則返回布爾值。不用搜索數組,這是一種高效、易于閱讀的解決方案。
const sections = ['contact', 'shipping'];
function displayShipping(sections) {
return sections.includes('shipping');
}
console.log(displayShipping(sections));
此外,還有indexOf()方法可用于檢查值以及查找索引。
13. 用falsy值縮短條件
在JavaScript的跨變量類型中,有一些值等效于false,包括:
- 布爾值false
- null
- 0
- NaN
- ' '
- " "
在 JavaScript 中,等效的==意味著兩個對象共享相同的值,但它們可能不是相同的類型。完全相同的===表示兩個對象類型相同,值也相同。這有什么用呢?
好吧,與其創建單獨的變量來保存布爾值,不如使用上述值作為默認值來報告false,如果沒有任何東西覆蓋的話。比如下面的例子,你需要檢查給定的員工是否接受過設備培訓(equipmentTraining)。這臺機器只需要最低級別的培訓,培訓水平并不重要。
因此,我們用if語句檢查equipmentTraining是否具有falsy值,即默認的' '。如果是,則執行if語句并返回員工未獲得授權。如果equipmentTraining包含除默認值以外的任何字符串,則表示具有truthy值,因此不會執行if語句。
const employee = {
name: 'Eric',
equipmentTraining: '',
}
if (!employee.equipmentTraining) {
console.log('Not authorized to operate machinery');
}
14. 通過繼承共享方法
繼承涉及在類之間共享屬性或方法。下面的示例中使用super標簽實現繼承,允許FlashCoupon中的構造函數訪問Coupon中的父構造函數。只需定義一次方法(在父類中),即可增強代碼的可讀性。代碼也變得更加模塊化,因為繼承器類可以專門用于給定任務。
注意,頂部的代碼框建立了父類Coupon,其屬性和方法共享到FlashCoupon,如FlashCoupon在其最后一行調用getExpirationMessage方法時看到的那樣。
class Coupon {
constructor(price, expiration) {
this.price = price;
this.expiration = expiration || 'Two Weeks';
}
getExpirationMessage() {
return `This offer expires in ${this.expiration}`;
}
}
export default Coupon;
import Coupon from './extend';
class FlashCoupon extends Coupon {
constructor(price, expiration) {
super(price);
this.expiration = expiration || 'two hours';
}
}
const flash = new FlashCoupon(10);
console.log(flash.getExpirationMessage());
15. 使用數組方法編寫較短的循環
最后一個小貼士,我們將深入探討數組優化的復雜性。循環是創建和填充數組的常用方法。但是,循環會導致代碼雜亂且難以閱讀。
因此,我們可以使用數組方法來實現類似的效果,例如for只需若干代碼行即可循環。以下面的for循環為例。
const prices = ['1.0', 'negotiable', '2.15'];
const formattedPrices = [];
for (let i = 0; i < prices.length; i++) {
const price = parseFloat(prices[i]);
if (price) {
formattedPrices.push(price);
}
}
console.log(formattedPrices);
我們可以通過三行map方法實現與上面代碼相同的效果。此方法創建了一個大小相等的數組,只有price屬性。然后使用parseFloat獲取價格的浮點值。
const prices = ['1.0', '2.15'];
const formattedPrices = prices.map(price => parseFloat(price));
console.log(formattedPrices)
總結
對簡潔代碼的追求是一個持續的旅程,因為最佳實踐會隨著語言的不斷發展而不斷改善。這個過程也是軟件開發樂趣的一部分,學習最佳實踐有助于開發人員真正掌握編程語言。大家加油!