如何简化重复的if语句

在实现代码逻辑时,免不了需要做一些判断和循环。尤其是在做搜索时,需要对搜索项的各个筛选项进行校验和判断,校验中存在一些区别但是大体结构是相似的,一直苦恼于这种情况应该如何优化,现分享一些方法可以帮助在代码中简化if判断的冗杂逻辑。

Array原型新增的方法

  • Array.prototype.every

当需要校验数组的每个值是否符合规范时,也许会这样子做:

var isAllNumber = true;
arr.map(function(val){
    if (isNaN(parseInt(val))) {
      isAllNumber = false;
    }
})
if (isAllNumber) {
  // ...
}

代码太长了,我们可以用every方法来减少代码数量。

if (array.every(val => !isNaN(parseInt(val)))) {
  // ...
}

可以看到,减少了6行代码!相同地,some函数也可以帮助我们简化判断逻辑语句。

  • Array.prototype.some
if (array.some(val => !isNaN(parseInt(val)))) {
  // ...
}

some和every的区别在于,some函数用于判断数组中是否至少有一个满足条件,every函数用于检测数组中每一个值是否满足条件。返回值为boolean值。

  • Array.prototype.includes

再看看这个例子:

if (res.errcode === '10001' || res.errcode === '10002') {
  // ...
}

哎?这个判断只有一行嘛,还需要优化嘛?如果后面还需要对’10003’、’10004’等errcode判断呢,我们就只能继续往后添加语句嘛?不用,用includes方法即可完成。

if (res.errcode.includes(['10001', '10002', '10003', '10004'])) {
  // ...
}

这样一来是更容易理解,二是也无需再添加||来判断了。

尽早return

在代码中,我习惯会将需要return的情况放到代码前面,相信大多数小伙伴也是这样做的。

function search (filter, page) {
  if (!filter) return;
  if (filter.every(val => val)) {
      // ...
      if (10 >= page) {
          // ...
      }
  }
}

上面例子确实在第一行就return掉了,但是后面的代码是可以提前return的,要不然要经过若干行代码才能看到对page的判断。

function search (filter, page) {
  if (!filter) return;
  if (!filter.every(val => val) return;
  if (10 >= page) {
    // ...
  }
}

这种提前return,一是可以避免多执行不必要的代码,二是代码逻辑会更加清晰一些。细心的伙伴会发现我习惯于将数字放到运算符的前面,准确说是将常量放到运算符的前面,这样是可以避免有时把运算符写成了赋值语句=的失误。

es6函数的默认参数和解析

在遇到undefined、null类型的变量时,我们经常使用或运算符对变量进行重新赋值。

count = count || 10;

es6中支持的参数有默认值,这点可以帮助我们去掉上面的语句。

function test (count = 10) {
  // ...
}

此外,es6还支持函数参数的解析功能。

function test({name} = {}) {
if (2 < name.length || 10 > name.length ) {
    // ...
}
}

此外,还有一些专门的库可以帮助我们减少检查语句,比如Lodash。

减少对switch的使用

我是比较少用到switch语句的,因为使用它就需要对每一个case加上break,还需要加上default。此外,case也不需要花括号括起来,case中判断的时候也是根据全等===进行判断的。看一下下面的例子:

 var type = '0';
switch(type) {
  case 0:
    // ...
    break;
  case 1:
    // ...
    break;
  default:
    break;
}

可是有些场景是需要switch的,如果不用switch的话,我们可以用对象替代,或者es6中的map方法。现在来列举一个map替代switch的demo。

const animals = new Map();
.set('dog', ['poodle', 'corgi'])
.set('fish', ['clown-fish', 'shark']);

function choicePets(animal) {
  return animals.get(animal) || [];
}

使用map可以轻松替代switch,而且代码逻辑会更加简单明了。

状态模式和策略模式

在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。

   var Add = function () {}
  Add.prototype.doAction = function (context) {
      // add的行为
      context.setState('add');
  }
 
  var Delete = function () {}
  Add.prototype.doAction = function (context) {
      // delete的行为
      context.setState('delete');
  }

首先创建了代表两个状态的对象,分别代表加和减。接下来就需要创建一个行为随着状态对象改变而改变的contex对象。

var Context = function () {};
Context,prototype.setState = function (state) {
  this.state = state;
}
Context,prototype.getState = function () {
  return this.state;
}

var context = new Context();
var add = new Add();
add.doAction(context);
context.getState(); // 'add'
var add = new Delete();
add.doAction(context);
context.getState(); // 'delete'

可以看到,context只需要实例化一次,并且会随着状态对象的改变而改变。在遇到多种有相同特点的不同状态的情况时,可以考虑用状态模式替代多个条件语句。此外,策略模式和状态模式相似,这里就不再细说了,感兴趣可以再看看策略模式~

发表评论