JavaScript-- 编程小技巧

293 阅读3分钟

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().