При работе с 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, чтобы узнать больше:
- Avoid Else, Return Early by Tim Oxley
- StackOverflow discussion on if/else coding style
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/блог…