如何培養良好的程式設計風格

付出發表於2018-03-13

前言: 雖然最近專案週期挺緊張的,晚上還是儘量擠出時間閱讀《編寫可維護的JavaScript》這本書籍。書籍總共分為三部分(程式設計風格,程式設計實踐,自動化),本文是第一部分程式設計風格中我認為比較精彩的片段(檢測值 && 格式化),也應用在了當前的專案中,整理出來跟大家分享,希望對大家在重構優化程式碼方面能夠帶來一定的幫助。

情景引入

在JavaScript中,我們常常會看到這種程式碼:變數和null的比較(這種寫法很有問題),用來判斷變數是否賦被賦予了一個合理的值。比如:

var Controller = {
    process: function (items) {
        if (item !== null) { // 不好的寫法
            items.sort()
            items.forEach(item => {
                // 一些程式碼
            })
        }
    }
}
複製程式碼

在這段程式碼中,process方法顯然是希望items是一個陣列,因為我們看到items擁有sort()和forEach().這段程式碼的意圖非常明顯;如果引數items不是一個陣列,則停止接下來的操作。我們來分析一下,這種寫法的問題在於和null比較並不能真正避免錯誤的發生。items的值可以是1,也可以是字串,甚至可以是任意物件。這些值都和null不相等,進而會導致process()方法一旦執行到sort()時就會出錯。

僅僅和null比較並不能提供足夠的資訊來判斷後續的程式碼執行是否真的安全。好在JavaScript為我們提供了多種方法來檢測變數的真實值。

檢測值

一、檢測原始值

在JavaScript中有5種原始型別:字串,數字,布林值,undefined,null

對於字串,數字,布林值,undefined,最佳選擇是使用typeof運算子

示例程式碼:

// 檢測字串
if (typeof name === "string") {
  // 執行程式碼
}

// 檢測數字
if (typeof count === "number") {
  // 一些程式碼
}

// 檢測數字
if (typeof found === "boolean") {
  // 一些程式碼
}

// 檢測undefined
if (typeof MyApp === "undefined") {
  // 一些程式碼
}
複製程式碼

對於null

null,一般不應用於檢測語句。正如上文情景引入中提到的,簡單地和null比較通常不會包含足夠的資訊以判斷值的型別是否合法。但有一個例外,如果所期望的值真的是null,則可以直接和null進行比較。 如果使用typeof運算子比較null,執行typeof null則返回'object',這是一種低效的判斷null的方法。 如果你需要驗證null,請直接使用恆等運算子(===)或非等運算子(!==) 示例程式碼: 輸入框的值的判斷

if (this.skuName !== null) {
  // 輸入框有值才執行請求介面
  this.copySkuBlock()
} else {
  // 提示輸入框要輸入值
  this.$message({
    type: 'error',
    message: '請輸入商品規格'
  })
}
複製程式碼

二、檢測引用值

在JavaScript鐘有4種引用型別:Object, Array, Date, 和Error。

示例程式碼:

// 檢測日期
if (value instanceof Date) {
  // 一些程式碼
}

// 檢測正規表示式
if (value instanceof RegExp) {
  // 一些程式碼
}

// 檢測Error
if (value instanceof Error) {
  // 一些程式碼
  throw value
}
複製程式碼

三、檢測函式

從技術上講, JavaScript中的函式是引用型別,同樣存在Function建構函式。由於instanceof運算子不能跨幀使用,typeof運算子則是檢測函式的最佳選擇

示例程式碼:

function myFunc () {
// 不好的寫法   不能跨幀使用,因為每個幀都有各自的Function建構函式
console.log(myFunc instanceof Function) // true
// 好的寫法  能跨幀使用, 但只能在IE9+使用
console.log(typeof myFunc === "function") // true
}
複製程式碼

四、檢測陣列

ES5將**Array.isArray()**的方法正式引入JavaScript,唯一的目的就是準確地檢測一個值是否為陣列,IE9+支援。

示例程式碼:

function isArray () {
  if (typeof Array.isArray === "function") {
    return Array.isArray(value)
  } else {
    return Object.prototype.toString.call(value) === "[object Array]"
  }
}
複製程式碼

五、檢測屬性

另外一種用到null(以及undefined)的場景是當檢測一個屬性是否在物件中存在時。比如:

// 不好的寫法: 和null比較
if (object[propertyName] !== null) {
  // 一些程式碼
}
複製程式碼

判斷物件中的屬性是否存在最好的方法是使用in運算子。 in運算子僅僅會簡單地判斷屬性是否存在,而不會去讀屬性的值。

示例程式碼:

A. 如果例項物件的屬性存在、或者繼承自物件的原型,in運算子都會返回true。比如:

if ("count" in object) {
  // 一些程式碼
}
複製程式碼

B. 如果你只想檢測例項物件的某個屬性是否存在,則使用hasOwnProperty()方法,僅支援IE9+

if (object.hasOwnproperty("count")) {
  // 一些程式碼
}
複製程式碼

因此,在判斷例項物件的屬性是否存在時,我更傾向於使用in運算子,只有在需要判斷例項屬性時才會用到hasOwnproperty,這樣做可以避免很多bug。

格式化

一、基本格式化

1.變數和函式, 都用小駝峰式命名,變數用名詞作字首,函式用動詞作字首。

2.禁止使用特殊值underfined,可以有效地確保只在一種情況下typeof才會返回“underfined”

二、註釋

1.使用註釋的原則 當程式碼不夠清晰時新增註釋,而當程式碼很明瞭時不應當新增註釋當程式碼不夠清晰時新增註釋,而當程式碼很明瞭時不應當新增註釋

2.文件註釋 開源專案中,強烈推薦用文件生成工具來生成文件註釋,比如YUIDoc或JSDoc Toolkit。 在Google內部的很多開源專案JSDoc Toolkit的應用非常廣泛,這兩者的區別在於,YUIDoc可以同時支援文件註釋中的HTML和Markdown格式,而JSDoc Toolkit 只支援HTML

三 語句和表示式

1.for迴圈

儘量用條件語句代替for迴圈中的continue,更加容易理解且不容易出錯

示例程式碼

  // 不好的寫法
  var values = [0, 1, 2, 3, 4, 5, 6],
    i,len
  for (i = 0, len = values.length; i < len; i++) {
    if (i === 2 ) {
    // 跳過本次迴圈
    continue
    }
    console.log('第' + i + '次迴圈')
  }
  // 好的寫法
  var values = [0, 1, 2, 3, 4, 5, 6],
    i,len
  for (i = 0, len = values.length; i < len; i++) {
    if (i !== 2 ) {
    console.log('第' + i + '次迴圈')
    }
  }
複製程式碼

2.for-in迴圈

for-in不僅遍歷物件的例項屬性,同樣還會遍歷從原型繼承來的屬性。因此,當遍歷自定義物件的屬性時,for-in遍歷物件會遍歷從原型繼承來的屬性,建議使用hasOwnProperty()方法來為for-in迴圈過濾出例項的屬性

示例程式碼

// 好的寫法
var prop
for (prop in object) {
   if (object.hasOwnProperty(prop)) {
      console.log('Property name is' + prop)
      console.log('Property value is' + object[prop])
   }
}
複製程式碼

我推薦總是在for-in迴圈中使用hasOwnProperty(), 除非你想查詢原型鏈,這時應當補充註釋,比如:

// 好的寫法
var prop
for (prop in object) {  // 包含對原型鏈的遍歷
      console.log('Property name is' + prop)
      console.log('Property value is' + object[prop])
}
複製程式碼

for-in迴圈是用來遍歷物件的,禁止用來遍歷數陣列成員

示例程式碼

// 不好的寫法
var values = [1, 2, 3],
    i
for (i in values) {
  console.log('Property name is' + i) // 0, 1, 2
  console.log('Property value is' + values[i]) // 1, 2, 3
}
複製程式碼

四、變數、函式、運算子

1.變數宣告

將區域性變數的定義作為函式內第一條語句;所有的var語句合併為一個語句,每個變數的初始化獨佔一行。賦值運算子應當對齊。對於那些沒有初始值的變數來說,它們應當出現在var語句的尾部。

示例程式碼

// 好的寫法
function doSomething () {
   // 區域性遍歷的定義
   var value = 10,
       result = value + 10,
       i,
       len
   for (i = 0, len = items.length; i < len; i++) {
     doOtherSomething(items[i])
   }
}
複製程式碼
  1. 嚴格模式

use strict 不僅適用於全域性,也適用於區域性,但是最好不要在全域性作用域中使用“use strict”模式

示例程式碼

// 不好的寫法 全域性的嚴格模式
'use strict'
function doSomething () {
  // 一些程式碼
}
// 好的寫法
(function () {
   'use strict'
   function doSomething () {
      // 一些程式碼
   }
   function doSomethingElse () {
     // 一些程式碼
   }
})
複製程式碼

3.運算子

由於JavaScript具有強制型別轉換機制的緣故,我們推薦不要使用==和!=,而是應當使用===和!==.

示例程式碼

// 不好的寫法  字串會被轉為數字,然後再進行比較
console.log(5 == '5') // true
// 好的寫法
console.log(5 === '5') // false
複製程式碼

4.函式

eval()

通用原則:嚴禁使用function,並且只在別無他法時使用eval()

總結

that's all, 以上就是我目前所有的對第一部分程式設計風格的理解以及應用。覺得對你開發有幫助的可以點贊收藏一波,如果我哪裡寫錯了,希望能指點出來。如果你有更好的想法或者建議,可以提出來在下方評論區與我交流。大家一起進步,共同成長。感謝[鞠躬]。

一起交流

個人的微信公眾號,付出的前端路,訂閱微信公眾號yhzg_gz(點選複製,在微信中新增公眾號貼上即可)

ps: 提高自己,常與異性交朋友

相關文章