程式碼重構技巧(二)

RobinsonZhang發表於2019-03-23

熔斷寫法

熔斷程式碼說的比較懸,其實就是將條件語句進行簡化的一種寫法,就和三目是if/else的一種簡化一樣。我們看下程式碼的對比效果。

// old codes 
if(isRight){
	fn();
}

// new codes 
isRight && fn();

// better codes 
isRight && fn && fn();
複製程式碼

邏輯或--預設值/預設執行

在es6中支援了引數預設值的寫法,解決的是某個引數在沒有傳入的時候取預設值的需求。那麼在之前我們是如何解決類似的需求的呢?我們通過邏輯或實現。

// now codes
function getAge(age = 12){
  let ageStr = `${age}歲`
	return ageStr
}
// old codes
function getAge(age ){
  let defaultAge = 12
  let _age = age || defaultAge
  let ageStr = `${_age}歲`
	return ageStr
}
複製程式碼

雖然我們已經不需要邏輯或來支援一些引數預設值的實現,但是我們在程式碼邏輯中類似的需求非常多,尤其一些很簡單的邏輯需求如果用過多的條件判斷,會讓程式碼變得很臃腫,因此當符合邏輯或需求場景時,我會建議用邏輯或執行。

let age = 12
// old codes
let isAdult = false
// normal codes
if(age && age >= 18){
	isAdult = true
}

// better codes
let isAdult = (age && age >= 18) ? true : false
// better codes
let isAdult = (age && age >= 18) || false


// 無論函式是否傳入:預設函式執行的案例 
// 假設我們要實現一段邏輯: 無論是否傳參 都執行一個預設函式或者邏輯
function print(fn){
	let defaultFn = ()=>{
  	console.log('預設執行')
  }
	(fn && fn()) || defaultFn()
}


print(()=>{
	console.log('自定義執行')
}) // 執行結果 : 自定義執行 預設執行
print() // 執行結果 : 預設執行


// 如果你期望是傳入時 執行傳入函式 否則 執行預設函式 那麼就和上面的預設引數一個邏輯了 ,
// 不同的是,我們很少將一個函式設為預設函式,而且在維護角度,我們也是期望預設函式維護在函式內部
function print(fn){
	let defaultFn = ()=>{
  	console.log('預設執行')
  }
  let _fn = fn || defaultFn
	return _fn()
}

複製程式碼

雙層邏輯轉換

邏輯值常識

經常有時候我們會寫一些邏輯值判斷,尤其是針對布林值的常見判斷。而有些冗餘的判斷是因為我們對一些值轉為布林值時的常識瞭解遠遠不夠。

比如我經常看到有的同學可能這樣寫邏輯:

if(classNumber === 0 || classNumber === undefined){
// codes here
}

// 如果你能明確的列出classNumber的所有可能情況,
//其實我們知道 數字0 以及 undefined null 都是屬於false的情況
if(!classNumber){
  // codes here 
}
複製程式碼

順帶陪大家複習下基本的資料型別轉為布林型資料的值。

image.png

案例

本條的重點不是介紹這些,而是介紹當我們在需要用某些值的判斷時可能直接使用存在誤差。尤其我在寫jsx語法的一些程式碼時,想使用如果某個值存在那麼就使用某個標籤或者元件。例如下面這樣:

// 作為常識 我們期望 classStatus 存在並且其值為1的時候才可執行 
{ classStatus && classStatus === 1  && <ClassInfo />}
// 但其實際執行結果 在不符合的時候輸出卻是這樣的 
0 
  
// 經過分析我們清楚了這個過程雖然執行到最後會有一個布林值,但之前的執行結果也一併執行而且返回了
// 於是有人程式碼就寫成了這樣,的確解決了問題,因為在程式碼執行中 前者只作為判斷不會作為輸出或者返回,
// 但多了沒用任何意義的null,除非我們需要額外的在否則的情況下返回其他
  {(classStatus && classStatus === 1)? <ClassInfo />:null}
  
// 所以我一般的建議是 一定要加雙層的布林邏輯,將其每段邏輯轉換為布林值,這樣就不會輸出額外的標識了 
{!!classStatus && classStatus === 1 && <ClassInfo />}
複製程式碼

延伸擴充

其實這樣的轉換為邏輯值在許多框架的原始碼中非常常見,因為我們一者不能保證使用者一定給的是布林值,另外也是出於程式碼更加嚴謹的角度,我們對傳入傳入的數值進行一次布林值轉換,比如vue 針對watcher 傳入是否深度監聽的deep部分,就加了這樣的程式碼。

image.png

相關文章