摘要:就讓咱們看看如下幾種常見的條件表達場景,如何寫的漂亮!
本文分享自華爲雲社區《如何寫出漂亮的條件表達式 - JavaScript 實現篇》,原文做者:查爾斯。程序員
條件表達式,是咱們在coding過程當中永遠躲不開的問題,也是咱們騙代碼行數最方便的東西(狗頭.jpg),但做爲一名程序員,咱們也要追求本身的「信達雅」,下面就讓咱們看看如下幾種常見的條件表達場景,如何寫的漂亮!數組
- 多條件語句
- 多屬性對象
- 替換Switch語句
- 默認參數與解構
- 匹配全部或部分條件
- 使用可選鏈和 Nullish 合併
多條件語句
多條件語句使用Array.includesapp
舉個例子函數
function printAnimals(animal) { if (animal === "dog" || animal === "cat") { console.log(`I have a ${animal}`); } } console.log(printAnimals("dog")); // I have a dog
這種寫法在條件比較少的狀況下看起來沒有問題,此時咱們只有 2 種動物,可是若是咱們有更多的條件須要判斷(更多的動物)呢?若是咱們繼續拓展判斷的條件,那麼代碼將會變得難以維護,並且邏輯會不清晰。工具
解決方法測試
可使用Array.includes來重寫條件語句ui
function printAnimals(animal) { const animals = ["dog", "cat", "hamster", "turtle"]; if (animals.includes(animal)) { console.log(`I have a ${animal}`); } } console.log(printAnimals("hamster")); // I have a hamster
在這裏,咱們建立了一個動物數組,以便將條件與代碼的其他部分分開提取。如今,若是咱們想要檢查任何其餘動物,咱們須要作的就是添加一個新的數組項。this
咱們還能夠在這個函數的範圍以外使用 animals 變量,以便在代碼的其餘地方重用它。這是一種編寫更清晰、更容易理解和維護的代碼的方法。不是嗎?編碼
多屬性對象
這是一個很是好的技巧來壓縮你的代碼,使它看起來更簡潔。讓咱們之前面的示例爲例,添加更多的條件。若是這個動物不是一個簡單的字符串,而是一個具備某些屬性的對象呢?url
因此如今的要求是:
- 若是沒有動物,拋出一個錯誤
- 打印動物的類型
- 打印動物的名字
- 打印動物的性別
const printAnimalDetails = (animal) => { let result; // declare a variable to store the final value // condition 1: check if animal has a value if (animal) { // condition 2: check if animal has a type property if (animal.type) { // condition 3: check if animal has a name property if (animal.name) { // condition 4: check if animal has a gender property if (animal.gender) { result = `${animal.name} is a ${animal.gender} ${animal.type};`; } else { result = "No animal gender"; } } else { result = "No animal name"; } } else { result = "No animal type"; } } else { result = "No animal"; } return result; }; console.log(printAnimalDetails()); // 'No animal' console.log(printAnimalDetails({ type: "dog", gender: "female" })); // 'No animal name' console.log(printAnimalDetails({ type: "dog", name: "Lucy" })); // 'No animal gender' console.log( printAnimalDetails({ type: "dog", name: "Lucy", gender: "female" }) ); // 'Lucy is a female dog'
上面的代碼它工做得很好,可是代碼很長,很難維護。若是不使用提示工具,可能會浪費一些時間來肯定右括號的位置。想象將會發生什麼若是代碼更復雜的邏輯。不少if...else的語句!
咱們可使用三元操做符、&&條件等來重構上面的函數,可是讓咱們使用多個返回語句來編寫更精確的代碼。
const printAnimalDetails = ({ type, name, gender } = {}) => { if (!type) return "No animal type"; if (!name) return "No animal name"; if (!gender) return "No animal gender"; // Now in this line of code, we're sure that we have an animal with all //the three properties here. return `${name} is a ${gender} ${type}`; }; console.log(printAnimalDetails()); // 'No animal type' console.log(printAnimalDetails({ type: dog })); // 'No animal name' console.log(printAnimalDetails({ type: dog, gender: female })); // 'No animal name' console.log(printAnimalDetails({ type: dog, name: "Lucy", gender: "female" })); // 'Lucy is a female dog'
在重構版本中,還包括解構和默認參數。默認參數確保若是咱們將 undefined 做爲參數傳遞給方法,咱們仍然有一個要解構的值,這裏是一個空對象 {}。
一般,代碼是在這兩種方法之間編寫的。
舉個例子
function printVegetablesWithQuantity(vegetable, quantity) { const vegetables = ["potato", "cabbage", "cauliflower", "asparagus"]; // condition 1: vegetable should be present if (vegetable) { // condition 2: must be one of the item from the list if (vegetables.includes(vegetable)) { console.log(`I like ${vegetable}`); // condition 3: must be large quantity if (quantity >= 10) { console.log("I have bought a large quantity"); } } } else { throw new Error("No vegetable from the list!"); } } printVegetablesWithQuantity(null); // No vegetable from the list! printVegetablesWithQuantity("cabbage"); // I like cabbage printVegetablesWithQuantity("cabbage", 20); // 'I like cabbage` // 'I have bought a large quantity'
如今,咱們有:
- 過濾無效條件的 if/else 語句
- 3 層嵌套的 if 語句(條件 一、2 和 3)
- 一個通用的規則是當發現無效條件時儘早返回。
一個通用的規則是發現無效的條件時儘早返回
function printVegetablesWithQuantity(vegetable, quantity) { const vegetables = ["potato", "cabbage", "cauliflower", "asparagus"]; // condition 1: throw error early if (!vegetable) throw new Error("No vegetable from the list!"); // condition 2: must be in the list if (vegetables.includes(vegetable)) { console.log(`I like ${vegetable}`); // condition 3: must be a large quantity if (quantity >= 10) { console.log("I have bought a large quantity"); } } }
經過這樣作,咱們減小了一個嵌套語句的級別。這種編碼風格很好,特別是當使用長if語句時。經過反轉條件並提早返回,咱們能夠進一步減小嵌套if。
請看下面的條件 2 是怎麼作的:
function printVegetablesWithQuantity(vegetable, quantity) { const vegetables = ["potato", "cabbage", "cauliflower", "asparagus"]; if (!vegetable) throw new Error("No vegetable from the list!"); // condition 1: throw error early if (!vegetables.includes(vegetable)) return; // condition 2: return from the function is the vegetable is not in // the list console.log(`I like ${vegetable}`); // condition 3: must be a large quantity if (quantity >= 10) { console.log("I have bought a large quantity"); } }
經過反轉條件 2 的條件,代碼再也不具備嵌套語句。當咱們有不少條件而且但願在任何特定條件不知足時中止進一步的處理時,這種技術是有用的。
所以,老是以減小嵌套和儘早返回爲目標,但不要過分。
替換Switch語句
讓咱們看一下下面的例子,咱們想要根據顏色打印水果:
function printFruits(color) { // use switch case to find fruits by color switch (color) { case "red": return ["apple", "strawberry"]; case "yellow": return ["banana", "pineapple"]; case "purple": return ["grape", "plum"]; default: return []; } } printFruits(null); // [] printFruits("yellow"); // ['banana', 'pineapple']
上面的代碼實現沒有錯誤,可是很冗長,一樣的結果可使用更簡潔的語法來實現。
// use object literal to find fruits by color const fruitColor = { red: ["apple", "strawberry"], yellow: ["banana", "pineapple"], purple: ["grape", "plum"], }; function printFruits(color) { return fruitColor[color] || []; }
一樣的,也可使用 Map 來實現:
// use Map to find fruits by color const fruitColor = new Map() .set("red", ["apple", "strawberry"]) .set("yellow", ["banana", "pineapple"]) .set("purple", ["grape", "plum"]); function printFruits(color) { return fruitColor.get(color) || []; }
Map是 ES5 以來可用的對象類型,它容許存 key-value。
對於上面的示例,可使用 Array.filter 實現相同的結果。
const fruits = [ { name: "apple", color: "red" }, { name: "strawberry", color: "red" }, { name: "banana", color: "yellow" }, { name: "pineapple", color: "yellow" }, { name: "grape", color: "purple" }, { name: "plum", color: "purple" }, ]; function printFruits(color) { return fruits.filter((fruit) => fruit.color === color); }
默認參數與解構
在使用 JavaScript 時,咱們老是須要檢查 null/undefined 並分配默認值或編譯中斷。
function printVegetablesWithQuantity(vegetable, quantity = 1) { // if quantity has no value, assign 1 if (!vegetable) return; console.log(`We have ${quantity} ${vegetable}!`); } //results } printVegetablesWithQuantity('cabbage'); // We have 1 cabbage! printVegetablesWithQuantity('potato', 2); // We have 2 potato!
若是蔬菜是一個對象呢?咱們能夠分配一個默認參數嗎?
function printVegetableName(vegetable) { if (vegetable && vegetable.name) { console.log(vegetable.name); } else { console.log("unknown"); } } printVegetableName(undefined); // unknown printVegetableName({}); // unknown printVegetableName({ name: "cabbage", quantity: 2 }); // cabbage
在上面的示例中,咱們但願打印蔬菜名(若是它可用)或打印 unknown。
咱們能夠經過使用默認參數&解構來避免條件if (vegetable && vegetable.name){}。
// destructing - get name property only // assign default empty object {} function printVegetableName({ name } = {}) { console.log(name || "unknown"); } printVegetableName(undefined); // unknown printVegetableName({}); // unknown printVegetableName({ name: "cabbage", quantity: 2 }); // cabbage
由於咱們只須要屬性名,因此咱們可使用 {name} 來改變參數的結構,而後咱們能夠在代碼中使用 name 做爲變量,而不是使用 vegetable.name。
咱們還將一個空對象 {} 賦值爲默認值,不然在執行 printVegetableName(undefined) 時,它將給出一個錯誤—— Cannot destructure property name of undefined or null,由於在 undefined 中沒有 name 屬性。
匹配全部或部分條件
咱們能夠經過使用這些Array方法來減小代碼行數。
下面的代碼,咱們想要檢查是否全部的水果都是紅色的:
const fruits = [ { name: "apple", color: "red" }, { name: "banana", color: "yellow" }, { name: "grape", color: "purple" }, ]; function test() { let isAllRed = true; // condition: all fruits must be red for (let f of fruits) { if (!isAllRed) break; isAllRed = f.color == "red"; } console.log(isAllRed); // false }
上面的代碼太過冗長,咱們能夠經過使用 Array.every 來減小代碼行:
const fruits = [ { name: "apple", color: "red" }, { name: "banana", color: "yellow" }, { name: "grape", color: "purple" }, ]; function test() { // condition: short way, all fruits must be red const isAllRed = fruits.every((f) => f.color == "red"); console.log(isAllRed); // false }
一樣的,若是咱們想要測試任何一個水果是不是紅色的,咱們可使用 Array.some:
const fruits = [ { name: "apple", color: "red" }, { name: "banana", color: "yellow" }, { name: "grape", color: "purple" }, ]; function test() { // condition: if any fruit is red const isAnyRed = fruits.some((f) => f.color == "red"); console.log(isAnyRed); // true }
使用可選鏈和 Nullish 合併
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/%E5%8F%AF%E9%80%89%E9%93%BE
這兩個功能對於 JavaScript 編寫更簡潔的條件很是有用。在編寫本文時,它們尚未獲得徹底的支持,可能須要使用Babel進行編譯。
可選連接可以處理相似樹的結構,而不須要顯式地檢查中間節點是否存在,而且Nullish與可選連接結合使用很是有效,能夠確保不存在節點的默認值。
舉個例子:
const car = { model: "Fiesta", manufacturer: { name: "Ford", address: { street: "Some Street Name", number: "5555", state: "USA", }, }, }; // to get the car model const model = (car && car.model) || "default model"; // to get the manufacturer street const street = (car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.street) || "default street"; // request an un-existing property const phoneNumber = car && car.manufacturer && car.manufacturer.address && car.manufacturer.phoneNumber; console.log(model); // 'Fiesta' console.log(street); // 'Some Street Name' console.log(phoneNumber); // undefined
所以,若是咱們想打印出來,若是汽車製造商來自美國,代碼應該是這樣的:
const isManufacturerFromUSA = () => { if ( car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.state === "USA" ) { console.log("true"); } }; checkCarManufacturerState(); // 'true'
能夠清楚地看到,對於更復雜的對象結構,這會變得多麼混亂。有一些第三方庫,如 lodash 或idx,它們有本身的功能。例如 lodash 有 _.get 方法。可是,在 JavaScript 語言自己中引入這個特性。
如下是這些新功能的工做原理:
// to get the car model const model = car?.model ?? "default model"; // to get the manufacturer street const street = car?.manufacturer?.address?.street ?? "default street"; // to check if the car manufacturer is from the USA const isManufacturerFromUSA = () => { if (car?.manufacturer?.address?.state === "USA") { console.log("true"); } };
目前在 Stage 3 階段。
以上就是基於JavaScript實現條件表達式的一些分享,但願對你能有所幫助~