9 рекомендаций по программированию в JavaScript | Улучшенный JavaScript

В мире JavaScript доступно множество инструментов и плагинов. Возможно, вы уже слышали о нескольких рекомендациях по написанию кода или правилах линтинга. Здесь, в этой статье, я перечислил несколько моих личных фаворитов с надлежащим объяснением кода. Эти рекомендации по написанию кода помогут вашему приложению быть более масштабируемым и удобным в сопровождении в коде JavaScript.

Темы:

  1. Используйте 1_
  2. Использование дополнительного оператора цепочки/Элвиса
  3. Использование условного обозначения объекта
  4. Использование hasOwnProperty
  5. Использование оператора спреда
  6. Использование Array.from
  7. Использование деструктуризации для извлечения ценности
  8. Перебор объектов с помощью операторов «из» и «в»
  9. Использование необязательных параметров

Использовать перечисление

Возможно, вы слышали о НЕТ ВОЛШЕБНЫХ ЧИСЛАХ. В нем говорится, что мы не должны создавать случайные числа, строки без значимого имени.

// TypeScript Sample
enum HTTP_RESPONSE_STATUS {
  OK = 200,
  CREATED,
  MOVED = 301,
  BAD_REQUEST = 400,
  UNAUTHORIZED,
  FORBIDDEN = 403,
}
console.log(HTTP_RESPONSE_STATUS);
/**
 * 
{
  '200': 'OK',
  '201': 'CREATED',
  '301': 'MOVED',
  '400': 'BAD_REQUEST',
  '401': 'UNAUTHORIZED',
  '403': 'FORBIDDEN',
  OK: 200,
  CREATED: 201,
  MOVED: 301,
  BAD_REQUEST: 400,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403
}
*/
export const createUsers = async (user) => {
  try {
    const newUser = await db.createUser(user);
    return { data: newUser, status: HTTP_RESPONSE_STATUS.OK };
  } catch (error) {
    return { error: error.message, status: HTTP_RESPONSE_STATUS.BAD_REQUEST };
  }
};

Приведенный выше пример написан на TypeScript. «enum» — это первоклассный член TypeScript. Однако enum недоступен в Обычном JavaScript. Вы можете использовать объект ключ-значение для того же самого.

const HTTP_RESPONSE_STATUS = Object.entries({
  OK: 200,
  CREATED: 201,
  MOVED: 301,
  BAD_REQUEST: 400,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403,
}).reduce((m, [key, value]) => {
  m[key] = value;
  m[value] = key;
  return m;
}, {});
console.log(HTTP_RESPONSE_STATUS);

Вы также можете заметить, что у нас есть объекты с перекрестными значениями и ключами. Это означает, что для каждого ключ-значение существует сопоставление ключ-значение. Это сопоставление ключ-значение полезно для проверки перекрестных ссылок.

Подробнее о реализации enum можно прочитать здесь, в разделе implement-enum-in-vanilla-javascript-using-proxy-class.

Использование дополнительного оператора цепочки/Элвиса

Оператор Элвиса определяется как ?.. Оператор Элвиса полезен для чтения значения свойства на глубоком уровне в цепочке свойств.

const user = {
  name: "Deepak",
  address: {
    street: "30 Lorem Address",
    pin: 67090,
  },
  fullAddress() {
    return `${this.address.street}, ${this.address.pin}`;
  },
};
// Case 1: Extract Property
console.log(user?.address?.street);
/// 30 Lorem Address
// Case 2: Extract Property and call function
console.log(user.fullAddress?.());
// 30 Lorem Address, 67090

В случае 1 вы извлекаете свойство street из address. Если адрес реквизита не определен, он вернется как undefined в первую очередь. В противном случае он будет перемещаться и получать значение улицы в адресе.

В случае 2 вы также можете найти свойство функции user.fullAddress?.() и вызвать его после проверки.

Реальный пример использования: безопасное получение языка из навигатора в SSR (рендеринг на стороне сервера)

const currentLanguage = window?.navigator?.language

Использование условного обозначения объекта

В ES6 представлено много приятного ясного синтаксиса, работающего вместе с классами и объектами. Если вы работали с синтаксисом и функциями класса ES6, вы можете использовать ту же нотацию функций класса с объектами. Посмотрите приведенные ниже примеры.

// Bag
const lukeSkywalker = "Luke Skywalker";
const atom = {
  value: 1,
  lukeSkywalker: lukeSkywalker, // Too verbose
  addValue: function (value) {
    return atom.value + value;
  },
};

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

// Good 
const atom = {
  value: 1,
  lukeSkywalker, // Short hand for Property
  addValue(value) { // Short hand for function
    return atom.value + value;
  },
};

Сокращение значительно упрощает назначение свойства объекту с его значением. А с синтаксисом () вам не нужно явно определять ключевые слова функции.

Использование hasOwnProperty

Возможно, вы видели проверку hasOwnProperty в ключевой итерации объекта. По сути, всякий раз, когда мы перебираем все свойства, мы хотим убедиться, что мы не включаем какое-то свойство-прототип. Для этого мы можем использовать метод hasOwnProperty для объектов.

class A {
  constructor() {
    this.a = "A";
  }
}
A.prototype.c = "c";
class B extends A {
  constructor() {
    super();
    this.b = "B";
  }
}
const b = new B();
for (let key in b) {
  if (b.hasOwnProperty(key)) {
    console.log("hasOwnProperty: ", key);
  } else {
    console.log("hasOwnProperty: != ", key);
  }
}
// hasOwnProperty:  a
// hasOwnProperty:  b
// hasOwnProperty: !=  c

В приведенном выше примере свойство "a" и "b" прямо и косвенно связано с объектом be. Однако свойство «c» доступно с использованием члена-прототипа. Однако, как правило, вы не должны перебирать свойство класса, используя for-in loop.

Вы можете прочитать больше о hasOwnPropertyздесьObject/hasOwnProperty.

Использование оператора спреда

Чтобы сделать отмель объекта или массива, вы можете использовать оператор спреда . Вы также можете копировать объекты с помощью Object.assign. Однако Object.assign более подвержен ошибкам, и его следует использовать только тогда, когда вместо этого вы хотите изменить фактический объект.

// good
const original = { a: 1, b: 2 };
const original2 = { c: 3, d: 4 };
const copy = { ...original, c: 3 }; 
// copy => { a: 1, b: 2, c: 3 }
const mergedObject = { ...original, ...original2 }; 
// { a: 1, b: 2, c: 3, d: 4 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
const originalArray = [1, 2, 3];
const originalArray2 = [4, 5, 6];
const copyArray = [...originalArray, 4]; // [1,2,3,4]
const without1 = originalArray.slice(1); //[2,3,4]
const mergedArray = [...originalArray, ...originalArray2]; ///[1,2,3,4,5,6]

Похожая идея, но плохой код.

const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this

Подробнее об objects--rest-spread можно прочитать здесь.

Использование Array.from

Array.from — один из малоиспользуемых методов. Используя Array.from, вы можете преобразовать любой массив, похожий на реальный массив.

const numbers = [1, 2, 3, 4];
const squares = [...numbers].map((num) => num * num);
console.log(squares); // [ 1, 4, 9, 16 ]
const squares2 = Array.from(numbers, (num) => num * num);
console.log(squares2); // [ 1, 4, 9, 16 ]

В приведенном выше примере вы можете видеть, что вы можете использовать оператор распространения и карту для создания нового массива из заданного списка чисел. Функция карты помогает создавать манипулировать возвращаемыми данными. Вы можете сделать то же самое с Array.from. Array.from принимает функцию сопоставления в качестве второго аргумента.

Array.from также полезен для преобразования элемента, похожего на массив, в массив. Однако, если у вас нет варианта использования картографа. Вместо Array.from рекомендуется использовать оператор распространения.

const foo = document.querySelectorAll('.foo');
// good
const nodes = Array.from(foo);
// best
const nodes = [...foo];

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

Оператор распространения используется для создания копии элементов. Деструктуризация используется для разрушения объекта (или массива).

const directions = [
  [-1, 0],
  [0, 1],
  [1, 0],
  [0, -1],
];
const getNighbours = (i, j) => {
  const [up, right, down, left] = directions;
  console.log(up, right, down, left);
  /// [ -1, 0 ] [ 0, 1 ] [ 1, 0 ] [ 0, -1 ]
};

Если вы работаете над задачей графа, вы можете легко создать массив точек каждого соседа и получить доступ, используя деструктурирование массива. Деструктурирование также полезно для возврата кортежа в качестве значения функции.

const getMaxValue = (array) => {
  let [index, max] = [-1, -Infinity];
  for (let i in array) {
    if (array[i] > max) {
      index = i;
      max = array[i];
    }
  }
  return [max, index];
};
const [max, i] = getMaxValue([1, 3, 5, 2, 7]);
console.log(max, i); // 7 4

Деструктуризация также полезна для доступа к значениям свойств объекта. Вы можете создавать переменные/константы из свойств объекта.

const MyReactComponents = ({ name, onSubmit }) => {
  console.log(name);
  onSubmit("On callback function");
};
MyReactComponents({ name: "Deepak", onSubmit: console.log });
// Deepak
// On callback function

Примечание. Также не рекомендуется использовать реструктуризацию массива для возврата более 3 параметров. Если вы хотите узнать больше о destructuring_assignment, перейдите по ссылке.

Итерация объектов с помощью операторов "из" и "в"

Вы всегда должны использовать итератор функций более высокого порядка вместе с Array. Однако разрыв цикла/ранний возврат с использованием функции более высокого порядка — утомительная задача. В случае, если вы работаете только со значениями. Вы можете использовать for-ofцикл.

const contains = (array, num) => {
  for (let value of array) {
    if (value === num) return true;
  }
  return false;
};
console.log(contains([1, 2, 3, 4], 5)); // false

Точно так же вы можете перебирать все ключи, используя цикл for-in.

const contains = (object, num) => {
  for (let key in object) {
    if (object[key] === num) return true;
  }
  return false;
};
console.log(contains({ a: 1, b: 2 }, 2)); // true

Если вас больше интересуют циклы. Вы можете прочитать мою статью как разорвать цикл в javascript.

Использование необязательных параметров

С ES6 вы можете определить значение по умолчанию для необязательного параметра для данной функции. Это очень полезно для function overload в JavaScript.

const request = (url, options = { method: "GET" }) => {
  return fetch(url, options);
};
console.log(request("test.com")); //get request
console.log(request("test.com", { method: "POST" })); //get request

Примечание. все необязательные параметры должны быть определены в конце аргументов. Может быть более 1 необязательных параметров.

Заключение

Охватить все рекомендации по кодированию в одной статье сложно. В следующих статьях я хотел бы обсудить другие более эффективные способы написания кода.

Использованная литература:

https://airbnb.io/javascript/

https://developer.mozilla.org/en-US/

https://google.github.io/styleguide/jsguide.html