Еще одно мнение о практике программирования.

Разные языки программирования имеют разные подходы к реализации одних и тех же задач. Самое главное для разработчика — использовать как можно больше сильных частей своего рабочего инструмента.

С самого начала JavaScript отличался от основных языков программирования того времени. При этом в маркетинговых целях дополнительно всегда имел модные черты (убедиться можно даже по названию).

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

Как и многие из вас, я начал свою практику программирования с языка ООП (исключая эксперименты с Паскалем). JavaScript обновляет синтаксический сахар ООП от выпуска до выпуска новой стандартной версии EcmaScript. Я считаю, что это нормальная практика, но в то же время я выбрал декларативный функциональный подход. JavaScript — один из лучших инструментов для того, чтобы начать следовать этому подходу.

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

let object = function mult(n) {
return mult.property * n;
}

Как видите, функция mult может иметь собственное свойство. Давайте используем эту функцию:

object.property = 2;
object(2); //returns 4

Мы можем установить любые значения свойств функции, как если бы объект.

Давайте перепишем нашу функцию mult без использования свойства self, потому что вы можете упустить одну важную вещь:

let object = n => n * 2;

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

С этого момента вы должны обрабатывать следующий код:

readFile((error, data) => /*Some logic here*/);

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

let handleFile = (error, file) => /*Some logic here*/;
readFile(handleFile);

Функция readFile использует обработчик внутри себя.

Использование ошибки в качестве первого аргумента функции-обработчика не является случайным. Это старое соглашение кода JavaScript для обработки асинхронных ошибок. Еще один подход к работе с асинхронным кодом — Promises. Вы могли часто видеть такой код (не обращайте внимания на ненужное использование синхронных функций как асинхронных, это для упрощения):

let getId = file => file.id;
let handleId = id => /*Some logic here*/;
readFile()
.then(file => {
return getId(file);
})
.then(id => {
return handleId(id);
});

Совершенно необходимо, да? Но теперь у нас есть новое важное знание: цепочка блоков then принимает один аргумент. И аргумент — это функция, которая в нашем новом понимании — всего лишь часть данных. Итак, давайте рефакторим наш код, чтобы он был декларативным:

readFile()
.then(getId)
.then(handleId);

Теперь декларативный. Мы избегали всех ненужных императивных инструкций в пользу обращения с функциями как с данными.