5 советов по написанию условных операторов в JavaScript

внешний интерфейс

banner

При работе с JavaScript нам приходится иметь дело с большим количеством условных выражений, вот пять советов, которые помогут вам писать условные выражения лучше/понятнее.

1. Используйте Array.includes в нескольких решениях

Давайте посмотрим на следующий пример:

// condition
function test(fruit) {
  if (fruit == 'apple' || fruit == 'strawberry') {
    console.log('red');
  }
}

На первый взгляд приведенный выше пример выглядит нормально. Однако, если вы добавите больше красных фруктов, таких какcherryа такжеcranberries, что случится? вы будете использовать больше||расширить условный оператор?

мы можем пройтиArray.includes(Array.includes)чтобы переписать приведенный выше условный оператор. следующим образом:

function test(fruit) {
  // extract conditions to array
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  if (redFruits.includes(fruit)) {
    console.log('red');
  }
}

мы извлекаемred fruits(условное суждение) в массив. Благодаря этому код выглядит чище.

2. Меньше гнездитесь, возвращайтесь раньше

Давайте расширим приведенный выше пример, включив в него еще два условия:

  • Если параметр фруктов не передан, выдать ошибку
  • Принимает параметр количества и печатает его, если оно превышает 10
function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  // condition 1: fruit must has value
  if (fruit) {
    // condition 2: must be red
    if (redFruits.includes(fruit)) {
      console.log('red');

      // condition 3: must be big quantity
      if (quantity > 10) {
        console.log('big quantity');
      }
    }
  } else {
    throw new Error('No fruit!');
  }
}

// test results
test(null); // error: No fruits
test('apple'); // print: red
test('apple', 20); // print: red, big quantity

Глядя на код выше, давайте двигаться:

  • 1 оператор if/else для фильтрации недопустимых условных операторов
  • 3 уровня вложенных операторов (условия 1, 2 и 3)

Мои личные рекомендацииВернуться раньше, когда обнаружено недопустимое условие.

/_ return early when invalid conditions found _/

function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  // condition 1: throw error early
  if (!fruit) throw new Error('No fruit!');

  // condition 2: must be red
  if (redFruits.includes(fruit)) {
    console.log('red');

    // condition 3: must be big quantity
    if (quantity > 10) {
      console.log('big quantity');
    }
  }
}

Возвращаясь раньше, мы уменьшаем один уровень вложенных операторов. Этот стиль кодирования великолепен, особенно если у вас есть длинные операторы if (представьте, что вам нужно прокручивать длинный путь, чтобы узнать, что есть оператор else, совсем не круто).

(Для приведенного выше примера) Мы можем еще больше уменьшить вложенность, инвертируя условие и возвращаясь раньше. Посмотрите ниже, как мы обрабатываем условие 2:

/_ return early when invalid conditions found _/

function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  if (!fruit) throw new Error('No fruit!'); // condition 1: throw error early
  if (!redFruits.includes(fruit)) return; // condition 2: stop when fruit is not red

  console.log('red');

  // condition 3: must be big quantity
  if (quantity > 10) {
    console.log('big quantity');
  }
}

Инвертируя условие 2, мы избегаем вложенных операторов. Этот трюк полезен: когда мы имеем дело с очень длинной логикой и хотим иметь возможность останавливаться, когда условия не выполняются.

И это не сложно сделать. Спросите себя, является ли эта версия (без условной вложенности) лучше/читабельнее, чем предыдущая версия (два уровня вложенности)?

Однако для себя я бы оставил предыдущую версию (с двумя уровнями вложенности). потому что:

  • Код короче и понятнее, а вложенные операторы if чище.
  • Инвертирование условий суждения может увеличить мыслительную нагрузку (увеличить когнитивную нагрузку)

Следовательно, следуетМинимизируйте вложенность и возвращайтесь раньше, но не переусердствуйте.. Если вам интересно, вы можете прочитать следующую статью и обсуждение на StackOverflow, чтобы узнать больше:

3. Использование параметров по умолчанию и деструктуризация

Я думаю, вы немного знакомы с приведенным ниже кодом, в JavaScript нам всегда нужно проверятьnull/undefinedзначение и укажите значение по умолчанию.

function test(fruit, quantity) {
  if (!fruit) return;
  const q = quantity || 1; // if quantity not provided, default to one

  console.log(`We have ${q} ${fruit}!`);
}

//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

На самом деле, мы можем исключить переменные, объявив параметры функции по умолчанию.q.

function test(fruit, quantity = 1) { // if quantity not provided, default to one
  if (!fruit) return;
  console.log(`We have ${quantity} ${fruit}!`);
}

//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

Это просто и интуитивно понятно! Обратите внимание, что каждое объявление имеет свой собственныйпараметры по умолчанию. Например, мы также можем датьfruitУстановите значение по умолчанию:function test(fruit = 'unknown', quantity = 1).

если нашfruitЧто может быть объектом? Можем ли мы назначить параметр по умолчанию?

function test(fruit) { 
  // printing fruit name if value provided
  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

В приведенном выше примере мы выводим название фрукта, если оно есть, иначе выводим unknown. Мы можем избежать предикатных условий, установив параметры по умолчанию и деструктурировавfruit && fruit.name.

// destructing - get name property only
// assign default empty object {}
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.

Мы также объявили пустой объект{}как значение по умолчанию. Если бы мы этого не сделали, вы бы получили сообщение об ошибке, что undefined или null не могут быть уничтожены. потому что в undefined нетnameАтрибуты.

Если вы не возражаете против использования сторонней библиотеки, есть несколько способов уменьшить количество проверок на null:

  • использоватьLodash getфункция
  • Библиотека Facebook с открытым исходным кодомidx(Используйте с бабелями)

Вот пример использования Lodash:

// Include lodash library, you will get _
function test(fruit) {
  console.log(__.get(fruit, 'name', 'unknown'); // get property name, if not available, assign default value 'unknown'
}

//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

ты сможешьJSBIN здесьЗапустите демонстрационный код, если вы поклонник функционального программирования, вы можете выбратьLodash fp, функциональная версия Lodash (метод изменен наgetилиgetOr).

4. Предпочитайте обход объекта операторам switch

Глядя на код ниже, мы хотим напечатать фрукты на основе цвета.

function test(color) {
  // use switch case to find fruits in 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']

Приведенный выше код кажется хорошим, но он несколько избыточен. Используя литерал объекта для достижения того же результата, синтаксис выглядит более кратким:

// use object literal to find fruits in color
  const fruitColor = {
    red: ['apple', 'strawberry'],
    yellow: ['banana', 'pineapple'],
    purple: ['grape', 'plum']
  };

function test(color) {
  return fruitColor[color] || [];
}

В качестве альтернативы вы можете использоватьMapдля достижения того же результата:

// use Map to find fruits in color
  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, который позволяет хранить пары ключ-значение.

Итак, должны ли мы запретить операторы switch? Не ограничивайте себя в этом. Лично я бы использовал обход объекта, когда это возможно, но не придерживался бы его строго и использовал то, что имеет больше смысла для текущей сцены.

У Todd Motto есть подробное сравнение операторов switch и объектов обхода, вы можете ткнутьздесьпроверить.

TL;DL;Грамматика рефакторинга

Для приведенного выше примера мы можем передать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) {
  // use Array filter to find fruits in color

  return fruits.filter(f => f.color == color);
}

Существует более одного способа достижения одного и того же результата, мы показали 4 выше. Кодирование радует!

5. Используйте Array.every/Array.some для всех/некоторых суждений

Последний трюк - использовать встроенный массив JavaScript для уменьшения количества строк кода. Посмотрите сейчас следующий код, мы хотим посмотреть, красным ли всеми фруктами:

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чтобы уменьшить количество строк кода:

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
}

Суммировать

Давайте вместе писать более читаемый код. Надеюсь, вы сможете узнать что-то новое из этой статьи.

Вот и все. Удачного кодирования!

оригинальныйScotch.IO/put-people-talk/5-…

Статья впервые опубликована:GitHub.com/still99/блог…

больше контента:GitHub.com/still99/блог…