摘要:就让咱们看看以下几种常见的条件表白场景,如何写的丑陋!
本文分享自华为云社区《如何写出丑陋的条件表达式 - JavaScript 实现篇》,原文作者:查尔斯。
条件表达式,是咱们在coding过程中永远躲不开的问题,也是咱们骗代码行数最不便的货色(狗头.jpg),但作为一名程序员,咱们也要谋求本人的“信达雅”,上面就让咱们看看以下几种常见的条件表白场景,如何写的丑陋!
- 多条件语句
- 多属性对象
- 替换Switch语句
- 默认参数与解构
- 匹配所有或局部条件
- 应用可选链和 Nullish 合并
多条件语句
多条件语句应用Array.includes
举个例子
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来重写条件语句
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
在这里,咱们创立了一个动物数组,以便将条件与代码的其余部分离开提取。当初,如果咱们想要查看任何其余动物,咱们须要做的就是增加一个新的数组项。
咱们还能够在这个函数的范畴之外应用 animals 变量,以便在代码的其余中央重用它。这是一种编写更清晰、更容易了解和保护的代码的办法。不是吗?
多属性对象
这是一个十分好的技巧来压缩你的代码,使它看起来更简洁。让咱们以后面的示例为例,增加更多的条件。如果这个动物不是一个简略的字符串,而是一个具备某些属性的对象呢?
所以当初的要求是:
- 如果没有动物,抛出一个谬误
- 打印动物的类型
- 打印动物的名字
- 打印动物的性别
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 cabbageprintVegetablesWithQuantity("cabbage", 20);// 'I like cabbage`// 'I have bought a large quantity'
当初,咱们有:
- 过滤有效条件的 if/else 语句
- 3 层嵌套的 if 语句(条件 1、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 colorconst fruitColor = { red: ["apple", "strawberry"], yellow: ["banana", "pineapple"], purple: ["grape", "plum"],};function printFruits(color) { return fruitColor[color] || [];}
同样的,也能够应用 Map 来实现:
// use Map to find fruits by colorconst 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); // unknownprintVegetableName({}); // unknownprintVegetableName({ 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); // unknownprintVegetableName({}); // unknownprintVegetableName({ 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...
这两个性能对于 JavaScript 编写更简洁的条件十分有用。在编写本文时,它们还没有失去齐全的反对,可能须要应用Babel进行编译。
可选链接可能解决相似树的构造,而不须要显式地查看两头节点是否存在,并且Nullish与可选链接联合应用十分无效,能够确保不存在节点的默认值。
举个例子:
const car = { model: "Fiesta", manufacturer: { name: "Ford", address: { street: "Some Street Name", number: "5555", state: "USA", }, },};// to get the car modelconst model = (car && car.model) || "default model";// to get the manufacturer streetconst street = (car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.street) || "default street";// request an un-existing propertyconst 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 modelconst model = car?.model ?? "default model";// to get the manufacturer streetconst street = car?.manufacturer?.address?.street ?? "default street";// to check if the car manufacturer is from the USAconst isManufacturerFromUSA = () => { if (car?.manufacturer?.address?.state === "USA") { console.log("true"); }};
目前在 Stage 3 阶段。
以上就是基于JavaScript实现条件表达式的一些分享,心愿对你能有所帮忙~
点击关注,第一工夫理解华为云陈腐技术~