JavaScript--编程小技巧
本文为个人翻译,若是造成您的误解,请查看原文。 来源
在任何编程语言中,代码都需要根据输入中给出的条件做出决策并执行动作。
例子:在一场游戏中,如果玩家生命为0,游戏就结束了;在天气应用中,如果在早晨查看,应该显示日出的图片,如果是在晚上查看,应该显示星星和月亮的图片;在本篇文章中,我们将会讨论所谓的条件语句是怎样在JavaScript 中工作的。
如果你使用JS工作,你将会使用很多涉及到条件的代码,这些条件语句看起来很容易学习,不过就是几个if/else语句而已,这里有一些有用的建议,帮助你写出更好,更整洁的条件语句代码。
目录如下:
- 1.Array.includes
- 2.Early exit / Return early: 及时的return语句
- 3.使用映射关系,而不是switch语句
- 4.默认参数和解构
- 5.匹配所有条件或匹配部分条件时使用 Array.every & Array.some
1.Array.includes
如果有多个条件,使用Array.includes 例子:
function prinAnimal(animal) {
if(animal === 'pig' || animal === 'dog') {
console.log(`I have ${animal}`)
}
}
console.log(prinAnimal('turtle'))
上面的代码对于只有两种动物时,看上去不错,然而,我们并不知道用户的输入的,如果还有其他动物呢,就要使用更多的 or 语句,那么代码将会更难维护,代码也不会整洁。
方案:
function prinAnimal(animal) {
const animals = ['dog', 'pig', 'cat', 'turtle']
if(animals.includes(animal)) {
console.log(`I have ${animal}`)
}
}
console.log(prinAnimal('turtle'))
在这里,创建一个动物数组,用来存放动物。创建这个数组是为了方便代码的其他部分从这里提取条件。
现在,我们想要检查其他动物,所做的就是向数组中增加新的数组项而已。
2.Early exit / Return early: 及时的return语句
这是一个非常酷的技巧去压缩你的代码并且保持整洁性。 继续以上一个例子为例,假如需要判断的条件不是简单的字符串,而是对象,或对象上的属性呢,应该怎么办。 现在我们考虑以下情况:
- 如果没有动物,抛出异常
- 输出动物种类
- 输出动物=名称
- 输出动物性别
const printAnimalDetails = animal => {
// 声明一个变量去存放最终结果
let result;
// 条件 1: 是否有动物
if (animal) {
// 条件 2: 动物是否有 type 属性
if (animal.type) {
// 条件 3: 动物是否有 name 属性
if (animal.name) {
// 条件 4: 动物是否有 gender 属性
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'
这段代码正确的运行了,但是很难去维护代码。如果没有没有代码规范工具的话,可能会浪费时间在没有闭合的 左右括号上。
我们可以使用三元操作符,&&操作符压缩代码,现在用多个 return语句来实现
const printAnimalDetails = ({type, name, gender } = {}) => {
if(!type) return 'No animal type';
if(!name) return 'No animal name';
if(!gender) return 'No animal gender';
// 在这个版本中,满足以上3个条件
return `${name} is a ${gender} ${type}`;
}
在这个重构版本中,也使用了解构和默认参数,这里解构了一个空对象。
另外一个例子:
function printVegetablesWithQuantity(vegetable, quantity) {
const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus'];
// 条件 1,vegetable 必须存在
if (vegetable) {
// 条件 2,必须是现有vegetable中的其中一个
if (vegetables.includes(vegetable)) {
console.log(`I like ${vegetable}`);
// 条件 3,quantity > 10
if (quantity >= 10) {
console.log('I have bought a large quantity');
}
}
} else {
throw new Error('No vegetable from the list!');
}
}
这个代码结构中包含:
- 1 if/else语句,用于过滤无效条件,
- 3 个嵌套的if语句。
常规的解决方法是遇到无效的条件及时 return
function printVegetablesWithQuantity(vegetable, quantity) {
const vegetables = ['potato', 'cabbage']
// 条件 1,vegetable 必须存在
if(!vegetable) return 'No vegetable'
// 条件 2,必须是现有vegetable中的其中一个
if(vegetables.includes(vegetable)) {
console.log(vegetable)
// 条件 3,quantity > 10
if(quantity >= 10) {
console.log(quantity)
}
}
}
这样,我们就降低了嵌套的层数.
核心在于:可以通过反转条件并尽早返回来进一步减少嵌套 始终以减少嵌套和及时返回为目标,但不要过度使用。
3.使用映射关系,而不是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']
这段代码看起来是没有错误的,但是有点冗长,我们可以使用映射关系,来解决这样冗长的代码。
为了描述这种“映射关系”,可以使用对象或Map来实现。 使用对象:
const fruitColor = {
red: ['apple', 'strawberry'],
yellow: ['banana', 'pineapple'],
purple: ['grape', 'plum']
};
function printFruits(color) {
return fruitColor[color] || []
}
使用Map结构
const fruitColor = new Map()
.set('red', ['apple', 'strawberry'])
.set('yellow', ['banana', 'pineapple'])
.set('purple', ['grape', 'grame'])
function printFruits(color) {
return fruitColor.get(color) || []
}
使用映射关系,代码就简洁了很多。 上面的结果,使用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)
}
4.默认参数和解构
在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!
加入上面的vegetable 是一个对象呢,为了防止编译错误,可能就要这样
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
可以通过解构和默认参数的形式来来避免 if (vegetable && vegetable.name) {} 这样的语句。
printVegetableName({name} = {}) {
console.log(name || 'unknown')
}
printVegetableName(undefined); // unknown
printVegetableName({ }); // unknown
printVegetableName({ name: 'cabbage', quantity: 2 }); // cabbage
5.匹配所有条件或匹配部分条件时使用 Array.every & Array.some.
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(),或Array.some()来缩减代码。
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
const isAllRed = fruits.every(f => f.color === 'red');
console.log(isAllRed); // false
}
同样,如果我们想要检查所有水果中有没有红色的水果,我们可以使用Array.some().