function test(fruit) { // 当值存在时打印 fruit 的值 if (fruit && fruit.name) { console.log (fruit.name); } else { console.log('unknown'); } } //test results test(undefined); // unknown test({ }); // unknown test({ name: 'apple', color: 'red' }); // apple
看上面这个例子,我们想打印 fruit 对象中可能存在的 name 属性。否则我们将打印unknown。我们可以通过默认参数以及解构从而避免判断条件 fruit && fruit.name
// 解构 - 仅仅获取 name 属性 // 为其赋默认值为空对象 function test({name} = {}) { console.log (name || 'unknown'); } // test results test(undefined); // unknown test({ }); // unknown test({ name: 'apple', color: 'red' }); // apple
由于我们只需要 name 属性,我们可以用 {name} 解构出参数,然后我们就能使用变量 name 代替 fruit.name。
我们也需要声明空对象 {} 作为默认值。如果我们不这么做,当执行 test(undefined) 时,你将得到一个无法对 undefined 或 null 解构的的错误。因为在 undefined 中没有 name 属性。
如果你不介意使用第三方库,这有一些方式减少null的检查:
使用 Lodash get函数
使用Facebook开源的idx库(with Babeljs)
这是一个使用Lodash的例子:
function test(fruit) { // 获取属性名,如果属性名不可用,赋默认值为 unknown console.log(__.get(fruit, 'name', 'unknown'); } // test results test(undefined); // unknown test({ }); // unknown test({ name: 'apple', color: 'red' }); // apple
你可以在jsbin运行demo代码。除此之外,如果你是函数式编程的粉丝,你可能选择使用 Lodash fp,Lodash的函数式版本(方法变更为get或者getOr)。
4.倾向于对象遍历而不是Switch语句
让我们看下面这个例子,我们想根据 color 打印出水果:
function test(color) { // 使用条件语句来寻找对应颜色的水果 switch (color) { case 'red': return ['apple', 'strawberry']; case 'yellow': return ['banana', 'pineapple']; case 'purple': return ['grape', 'plum']; default: return []; } } // test results test(null); // [] test('yellow'); // ['banana', 'pineapple']
上面的代码看起来没有错误,但是我找到了一些累赘。用对象遍历实现相同的结果,语法看起来更简洁:
const fruitColor = { red: ['apple', 'strawberry'], yellow: ['banana', 'pineapple'], purple: ['grape', 'plum'] }; function test(color) { return fruitColor[color] || []; }
或者你也可以使用 Map实现相同的结果:
const fruitColor = new Map() .set('red', ['apple', 'strawberry']) .set('yellow', ['banana', 'pineapple']) .set('purple', ['grape', 'plum']); function test(color) { return fruitColor.get(color) || []; }
Map是一种在 ES2015 规范之后实现的对象类型,允许你存储 key 和 value 的值。
但我们是否应当禁止switch语句的使用呢?答案是不要限制你自己。从个人来说,我会尽可能的使用对象遍历,但我并不严格遵守它,而是使用对当前的场景更有意义的方式。
Todd Motto有一篇关于 switch 语句对比对象遍历的更深入的文章,你可以在这个地方阅读
TL;DR; 重构语法
在上面的例子,我们能够用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 test(color) { return fruits.filter(f => f.color == color); }
有着不止一种方法能够实现相同的结果,我们以上展示了 4 种。
5.对 所有/部分 判断使用Array.every & Array.some
这最后一个建议更多是关于利用 JavaScript Array 的内置方法来减少代码行数。看下面的代码,我们想要检查是否所有水果都是红色:
const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { let isAllRed = true; // 条件:所有水果都是红色 for (let f of fruits) { if (!isAllRed) break; isAllRed = (f.color == 'red'); } console.log(isAllRed); // false }
代码那么长!我们可以通过 Array.every减少代码行数: