条件和循环是日常编程中最重要的方式,如何优雅的书写条件判断和循环呢,这里有五条建议,并不是什么高深的技能,而是应该在日常工作中加强这种书写意识
Array.includes
针对多重条件判断,可以使用Array.includes代替,不仅可以优雅代码,同时扩展性来的更强。比如如下代码
function test(fruit) {
if (fruit == 'apple' || fruit == 'strawberry') {
console.log('red');
}
}
经过优化后,代码可以如下
function test(fruit) {
// extract conditions to array
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (redFruits.includes(fruit)) {
console.log('red');
}
}
少嵌套,早返回
我们先看如下代码存在哪些问题
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// condition 1: fruit must has value
if (fruit) {
// condition 2: must be red
if (redFruits.includes(fruit)) {
console.log('red');
// condition 3: must be big quantity
if (quantity > 10) {
console.log('big quantity');
}
}
} else {
throw('No fruit!');
}
}
条件判断嵌套过多,试想,我想知道不满足条件逻辑,还需要判断代码的最后,这是很糟糕的阅读代码体验。优化技巧对于不满足条件,及早返回(inverting the conditions & return early)。我们在书写代码的时候,应该更多的思考如何减少if嵌套,代码看上去瞬间优雅很多,比如优化如下
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (!fruit) throw('No fruit!'); // condition 1: throw error early
if (!redFruits.includes(fruit)) return; // condition 2: stop when fruit is not red
console.log('red');
// condition 3: must be big quantity
if (quantity > 10) {
console.log('big quantity');
}
}
缺省参数与解构
在JS书写代码中,我们经常需要检查null/undefined
值,且赋予一个缺省值,比如如下代码
function test(fruit, quantity) {
if (!fruit) return;
const q = quantity || 1; // if quantity not provided, default to one
console.log(`We have ${q} ${fruit}!`);
}
在ES6来临后,函数缺省参数和解构,我们就可以对这种代码说bye了,在形参的时候可以指定默认值
function test(fruit, quantity = 1) { // if quantity not provided, default to one
if (!fruit) return;
console.log(`We have ${quantity} ${fruit}!`);
}
上面只是演示了,原始类型的情况,如果参数是对象呢,你知道如果我们取空值的属性就会报错,如何避免这种情况,增强程序的健壮性呢,答案就是解构
// 优化前
function test(fruit) {
// printing fruit name if value provided
if (fruit && fruit.name) {
console.log (fruit.name);
} else {
console.log('unknown');
}
}
// 优化后
function test({name} = {}) {
console.log (name || 'unknown');
}
Map/Object
我们可以通过Map数据类型或Object替换switch或if语句,这是一个很实用的技能,不仅可以减少判断或循环次数,而且更容易扩展,来个例子
function test(color) {
// use switch case to find fruits in color
switch (color) {
case 'red':
return ['apple', 'strawberry'];
case 'yellow':
return ['banana', 'pineapple'];
case 'purple':
return ['grape', 'plum'];
default:
return [];
}
}
使用Object优化十分简单,我们这里看看使用Map如何做
function test(color) {
// use Map to find fruits in color
const fruitColor = new Map()
.set('red', ['apple', 'strawberry'])
.set('yellow', ['banana', 'pineapple'])
.set('purple', ['grape', 'plum']);
return fruitColor.get(color) || [];
}
使用Array.filter函数达到同样目的
function test(color) {
// use Array filter to find fruits in color
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' } ];
return fruits.filter(f => f.color == color);
}
Array迭代器函数
使用Array.every和Array.some减少循环,直接用代码演示下吧
function test(fruits) {
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
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
}
function test(fruits) {
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
// condition: short way, all fruits must be red
const isAllRed = fruits.every(f => f.color == 'red');
console.log(isAllRed); // false
}
function test(fruits) {
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
// condition: if any fruit is red
const isAnyRed = fruits.some(f => f.color == 'red');
console.log(isAnyRed); // true
}