前言: 雖然最近專案週期挺緊張的,晚上還是儘量擠出時間閱讀《編寫可維護的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])
}
}
複製程式碼
- 嚴格模式
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: 提高自己,常與異性交朋友