JavaScript - это простой в освоении язык программирования. Легко писать программы, которые работают и что-то делают. Однако сложно написать чистый код JavaScript.

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

Рефакторинг конструкторов в классы

В JavaScript класс - это просто синтаксический сахар для функций-конструкторов, поэтому на самом деле они являются функциями.

Все классы обеспечивают более интуитивный синтаксис для функций конструктора, избегая работы с прототипами и используя call для вызова функций родительского конструктора, когда мы расширяем другой конструктор.

Например, вместо написания:

function Foo(name) {
  this.name = name;
}
Foo.prototype.getName = function() {
  return this.name;
}

Мы пишем:

class Foo {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}

Как мы видим, с синтаксисом класса ясно, где находится конструктор и какие методы экземпляра содержит наш класс с синтаксисом класса.

Вместо того, чтобы прикреплять методы экземпляра к прототипу функции-конструктора, мы добавляем его в класс.

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

Если мы хотим сделать наследование, вместо того, чтобы писать:

function Animal(name) {
  this.name = name;
}
Animal.prototype.getName = function() {
  return this.name;
}
function Cat(name) {
  Animal.call(this, name);
}
Cat.prototype.constructor = Animal;

Мы пишем:

class Animal {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}
class Cat extends Animal {
  constructor(name) {
    super(name);
  }
}

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

Мы также проясняем, что мы расширяем класс Animal с помощью ключевого слова extends вместо того, чтобы самому устанавливать родительский конструктор в дочернем конструкторе.

По возможности избегайте традиционных функций

До ES2015 во всем использовались традиционные функции. Он используется для инкапсуляции кода, используется в качестве блоков, используется для конструкторов, как мы использовали выше, для обратных вызовов и т. Д.

Большинство этих случаев было заменено другими конструкторами, которые были представлены в ES2015.

Если мы хотим инкапсулировать код, мы можем использовать блоки. Например, вместо написания выражения немедленно вызываемой функции (IIFE) следующим образом:

(function() {
  let x = 1;
  console.log(x);
})()

Вместо этого мы можем написать:

{
  let x = 1;
  console.log(x);
}

Второй пример короче, и нам нужно только ограничить блок фигурными скобками.

Переменная x недоступна за пределами блока с приведенным выше кодом.

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

module.js

export const x = 1;
const y = 2;
const z = 3;
export default y;

index.js

import { x } from "./module";
import y from "./module";
console.log(x, y);

В приведенном выше коде мы открываем только то, что у нас есть, при экспорте с ключевым словом export. Следовательно, x и y доступны для импорта из другого модуля.

Как видим, x и y были импортированы из module.js. Но z не могло быть, потому что он не экспортировался.

Следовательно, нам больше не нужны следующие IIFE:

const module = (function() {
  const x = 1;
  const y = 2;
  const z = 3;
  return {
    x,
    y
  }
})();

Приведенный выше код длиннее и без надобности использует функцию. Кроме того, по мере того, как функция имеет больше членов, она становится длиннее, и иметь длинные функции - не лучшая идея.

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

const arr = [1, 2, 3].map(function(a) {
  return a * 2;
})

Мы должны написать:

const arr = [1, 2, 3].map(a => a * 2)

Он короче, поэтому нам не нужно столько печатать, как не нужно вводить ключевое слово function. Кроме того, возврат является неявным для функций с одной линией стрелки. И нам также не нужно беспокоиться о значениях this и arguments, поскольку стрелочные функции не привязываются ни к одному из этих значений.

Заключение

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