1. 数组方法 Array.includes
我们可以通过使用 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
这里,我们创建来一个动物数组,所以条件语句可以和代码的其余部分抽象分离出来。现在,如果我们想要检查任何其他动物,我们只需要添加一个新的数组项。
2. 提前退出 / 提前返回
我们能通过条件倒置和提前返回,进一步减少嵌套的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,代码没有嵌套语句了。这种技术在我们有很多条件并且当任何特定条件不匹配时,我们想停止进一步处理的时候特别有用。
3. 用对象字面量或Map替代Switch语句
相同的功能能用对象字面量以更清晰的语法实现:
// 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
允许保存键值对,是自从ES2015以来可以使用的对象类型。
对于上面的例子,相同的功能也能用数组方法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
值并赋默认值,否则可能编译失败
我们能通过使用默认参数和解构来避免条件语句 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 }
解构参数,然后我们就能在代码中使用 name
作为变量,而不是 vegetable.name
。
我们还赋了一个空对象 {} 作为默认值,因为当执行 printVegetableName(undefined)
时会得到一个错误:不能从 undefined
或 null
解构属性 name
,因为在 undefined
中没有name
属性。
5. 用 Array.every & Array.some 匹配全部/部分内容
我们能用 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
}
6. 使用可选链和空值合并
如果我们想要打印是否车辆生产商来自美国,代码将看起来像这样:
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');
}
}
这看起来很美观并容易维护。它已经到 TC39 stage 3 阶段,让我们等待它获得批准,然后我们就能无处不在地看到这难以置信的语法的使用。