通过这样做,我们减少了一个嵌套语句的级别。这种编码风格很好,特别是当使用长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 来减少代码行: