Главная » Статьи » Лучшие практики JavaScript — меняем старое на новое

Лучшие практики JavaScript — меняем старое на новое

Лучшие практики JavaScript - меняем старое на новое

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

С тех пор как был представлен ES6, новые конструкции заменяют старые по веским причинам. Они намного короче, чище и проще для понимания.

В этой статье мы рассмотрим, какие старые конструкции можно заменить новыми, включая замену then на async и await, замену объектов словаря на Map, замену apply на оператор распространения и замену конструкторов функций синтаксисом класса.

Замена then на async / await

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

Promise.resolve(1) .then((val) => { console.log(val); return Promise.resolve(2); }) .then((val) => { console.log(val); return Promise.resolve(3); }) .then((val) => { console.log(val); })

С введением синтаксиса async и await, который является просто сокращением для многократного вызова метода then, мы можем написать этот код так:

(async () => { const val1 = await Promise.resolve(1); console.log(val1); const val2 = await Promise.resolve(2); console.log(val2); const val3 = await Promise.resolve(3); console.log(val3);
})();

Они оба выводят 1, 2 и 3, но второй фрагмент кода намного короче. Это настолько чисто, что нет причин возвращаться к старому синтаксису.

Кроме того, мы можем просматривать промисы и запускать их один за другим, используя цикл for-await-of. Мы можем перебрать промисы, которые у нас есть выше, переписав код следующим образом:

(async () => { const promises = [ Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), ] for await (let p of promises) { const val = await p; console.log(val); }
})();

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

Замена объектов словаря на Map

ES6 также представил конструктор Map, который позволяет создавать хеш-карты или словари, не используя для этого объекты JavaScript со строковыми ключами.

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

const dict = { 'foo': 1, 'bar': 2
}

мы пишем:

const dict = new Map([ ['foo', 1], ['bar', 2]
])

Затем мы можем получить запись, используя метод get следующим образом:

console.log(dict.get('foo'));

Мы можем установить значение существующей записи по ключу записи с помощью метода set:

dict.set('foo', 2);

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

dict.has('baz');

У нас также есть методы keys и entries, чтобы получить все ключи Map и все записи соответственно. Например, мы можем написать:

console.log(dict.keys());

Чтобы получить объект итератора с ключами Map. Это означает, что мы можем перебрать их с помощью цикла for…of или преобразовать в массив с помощью оператора распространения.

Точно так же метод entries возвращает объект итератора со всеми записями в Map, причем каждая запись является массивом [key, value]. Также есть метод value для получения объекта итератора со всеми значениями в Map.

Мы также можем использовать в качестве ключей другие примитивные значения. Если мы используем объекты, мы не можем получить значение обратно, когда ищем их, так как поиск выполняется оператором ===, который возвращает false, так как 2 объекта не содержат одинаковую ссылку, даже если они имеют одинаковое содержимое.

Эти методы недоступны в обычном объекте. Кроме того, мы можем случайно получить или изменить свойства прототипа объекта вместо его собственных, если будем использовать цикл for…in. Поэтому нет больше причин использовать обычный объект в качестве словаря.

Замена Apply на Spread

Если мы не хотим изменять значение this внутри функции, нет особых причин использовать в функциях метод apply. Если мы хотим вызвать функцию только с несколькими аргументами, мы можем использовать при передаче массива оператор распространения для наших аргументов следующим образом:

const arr = [1, 2, 3, 4, 5];
const add = (...args) => args.reduce((a, b) => a + b, 0);
console.log(add(...arr));

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

Замена функции конструктора классами

Еще одна замечательная функция ES6 — синтаксис класса для функций конструктора. Это просто синтаксический сахар, который делает функцию конструктора похожей на класс. Преимущество заключается в том, что это облегчает наследование. К примеру, если мы хотим наследовать от функции конструктора, мы должны написать что-то вроде этого:

function Person(name) { this.name = name;
} function Employee(name, employeeCode) { Person.call(this, name); Employee.prototype.constructor = Person; this.employeeCode = employeeCode;
} const employee = new Employee('Joe', 1);
console.log(employee)

Этот синтаксис выглядит странно для объектно-ориентированных языков на основе классов, таких как Java. Тем не менее, синтаксис класса делает вещи более знакомыми для разработчиков, которые использовали другие языки больше, чем JavaScript. Мы можем переписать приведенный выше код следующим образом:

class Person { constructor(name) { this.name = name; }
} class Employee extends Person { constructor(name, employeecode) { super(name); this.employeecode = employeecode; }
} const employee = new Employee('Joe', 1);
console.log(employee)

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

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

С синтаксисом класса нам не нужно беспокоиться об этом. Если мы забыли выполнить вызов super, как в приведенном ниже коде:

class Person { constructor(name) { this.name = name; }
} class Employee extends Person { constructor(name, employeecode) { this.employeecode = employeecode; }
} const employee = new Employee('Joe', 1);
console.log(employee)

Мы получим ошибку «Uncaught ReferenceError: Must call super constructor in derived class before accessing ‘this’ or returning from derived constructor». Это еще одна возможность для ошибок.

Мы не получим никакой ошибки, если опустим Person.call, подобно как в функции конструктора Employee, так как браузер не знает, что мы хотим наследовать Employee от Person.

Кроме того, когда мы регистрируем прототип employee, мы получаем, что прототип employee является Person, как и ожидается с синтаксисом класса. Тем не менее, мы не получим это, если не вставим Employee.prototype.constructor = Person;, что легко забыть.

Заключение

Async и await и for-await-of являются новыми конструкциями, которые делают цепочки промисов намного чище. Поэтому гораздо лучше использовать их, а не then.

for-await-of также позволяет нам перебирать через цикл промисы, которые генерируются динамически, и которые мы не можем создать только с помощью then или async и await.

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

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

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

Автор: John Au-Yeung

Источник: https://levelup.gitconnected.com

Редакция: Команда webformyself.