Альтернативы решения типичных задач

Альтернативы решения типичных задач

Maksym Pohribniak

Мне часто приходится выступать в роли ментора:

  • в офисе (для junior разработчиков)
  • на курсах (для совсем начинающих)

И в связи с этим приходится читать много javascript кода написанного неопытными разработчиками. Также, схожий код часто встречается у разработчиков с другим основным языком (не JavaScript).

Я собрал подборку простых кусков кода, которые по моему мнению можно более красиво и понятно(не всегда) переписать.

Это не значит, что код, в примерах ниже, плохой и так писать неверно. Я лишь предлагаю альтернативы.

Далее по пунктам:

0.

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


Вам не нужно четко сравнивать булевые значения в условных выражения с true/false. Код:

if (v0 === false) {}
if (v1 === true && v2 === true) {}

Полностью аналогичен следующему:

if (!v0) {}
if (v1 && v2) {}

Возвращая булевое значение из функции, не нужно делать так:

function isEven(value){
if (value % 2 === 0) {
return true;
} else {
return false;
}
}

Если вы пишете как в примере выше, вы не понимаете, что такое логическое значение и как с ними работать.

if (condition) {
  answer = true;
} else {
  answer = false;
}

это просто излишне многословная версия условия

answer = condition // или !!condition

Функцию isEven можно переписать так:

function isEven() {
  return value % 2 === 0;
}


1.

Нужно узнать является переменная letter гласной буквой. Как эту задачу решают чаще всего? Так как и понимают. Через if и "или"(||):

if (
 letter === 'a' ||
 letter === 'e' ||
 letter === 'u' ||
 letter === 'o' ||
 letter === 'i') {
 // do something
}

Более декларативно этот кусок можно переписать таким образом:

if (['a', 'e', 'u', 'o', 'i'].includes(letter)) {
 // do something
}

Мы храним все допустимые варианты в одном месте и нам просто разширять возможности условия.


2.

Есть список,

const files = [ 
'index.js', 
'ui.js',
 'select.js'
];

его нужно расширить в зависипости от определенных условий,

if (someFlag) {
 files.push('f1.js');
}

if (anotherFlag) {
  files.push('q1.js');
} else {
  files.push('q2.js');
}

добавить тот или иной элемент или добавлять/не добавлять вовсе.

Описанный выше код можно сделать более лаконичным с перебирающими методами массивов:

const files = [
  'index.js'
  'index.js',
  'ui.js',
  'select.js'
  someFlag && 'f1.js',
  anotherFlag ? 'q1.js' : 'q2.js'
].filter(Boolean);

Если someFlag будет приведен в false, то он откинется методом фильтр. Плюс больше не нужно создавать if'ы. Перебирающие методы позволяют делать наш код более декларативным.

Например следующий код:

if (variable1 === 'some value' && variable2 === 'another value' && variable3 &&
 (variable4 === 'some value' || variable5 === 'another value' || variable6)) {
// do something
}

Условие получилось очень длинным и читать его затруднительно.

Конечно, можно разбить его на несколько переменных, но посмотрите на следующий вариант:

const requiredExpressions = [
variable1 === 'some value',
variable2 === 'another value',
variable3
].every(Boolean);
const optionalExpressions = [
 variable4 === 'some value',
 variable5 === 'another value',
 variable6
].some(Boolean);
if (requiredExpressions && optionalExpressions) {
 // do something
}


Конечно, теперь он выгляди намного длиннее чем в первом варианте, но Методы some и every четко дают понять о происходящем, и код читается проще.


3.

Иногда, нужно проверить пустой ли обьект, и встроенного метода для этого в JavaScript нет. Вариант который я встречал выглядит так:

function isEmpty(obj) {
  for (let prop in obj) {
   if (obj[prop]) {
    return false;
   }
}
return true;
}
isEmpty(objectToCheck)

Примерно такой же ответ в топах ответов на этот вопрос на Stackoverflow.

Весь код выше можно заменить одной строкой:

Object.keys(objectToCheck).length === 0

Метод Object.keys собирает ключи объекта. Соответственно если их нет –возвращает пустой массив.


4.

Преобразование данных. Мы получаем объект в свойствах которого числа почему-то хранятся в виде строк. Для дальнейшей работы с ним нужно сделать их числами. Как чаще всего решают эту задачу:

const data = {
value1: '1234',
value2: '34',
value3: '52'
}
const imperativeDataNumberValues = {};

for (let property in inputObject) {
  if (inputObject.hasOwnProperty(property)) {
   imperativeDataNumberValues[property] = parseFloat(inputObject[property]);
  }
}


Перебираем ключи, получаем значение, с помощью функции parseFloat делаем из него число. Далее записываем пару ключ/значение в созданный пустой объект. Вполне логично. А теперь декларативный вариант:

const dataNumberValues = Object.keys(inputObject)
  .reduce((acc, next) => ({ ...acc, [next]: parseFloat(inputObject[next]) }), {});

Возможно, этот метод окажется менее читабельным, но если у вас и команды есть должный опыт работы с перебирающими методами – проблем возникнуть не должно.


6.

Флаги аргументы. При расширении функционала, иногда, добавление аргумента флага может показаться вам хорошей идеей, но, поверьте, это не так.


function createFile(name, isPublic) {
 if (isPublic) {
   fs.create(`./public/${name}`);
  } else {
   fs.create(name);
  }
}

Вместо этого создайте 2 функции, каждая из которы выполнит свою задачу:

function createFile(name) {
 fs.create(name);
}
function createPublicFile(name) {
 createFile(`./public/${name}`);
}

Чем такой подход лучше читать здесь.

5.

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

Допустим, вам нужно задать различные значения 3-м переменным в зависимости от переменной someFlag:

let v1, v2, v3;

if (someFlag) {
 v1 = '+v1';
  v2 = '+v2'
  v2 = '+v3'
} else {
  v1 = '-v1';
  v2 = '-v2';
  v2 = '-v3';
}

Используем деструктуризацию и приведение типов чтобы перезаписать это пример в одну строку:

let [v1, v2, v3] = [['+v1', '+v2', '+v3'], ['-v1', '-v2', '-v3']][+!someFlag];

Ставьте лайк посту, если разобрались как работает данный пример 😊.

Спасибо за внимание!

Report Page