33 приема оптимизации JavaScript, которые вы должны знать в 2021 году
Предлагаем вашему вниманию подборку полезных техник и хитростей для оптимизации кода на JavaScript. Она будет интересна не только изучающим язык новичкам, но и опытным программистам. Обсудить Хороший разработчик всегда должен учиться чему-то новому и совершенствовать навыки, которые у него уже есть. Поэтому сейчас мы будем учиться писать более чистый и понятный код! Ниже вы найдете большую подборку кратких вариантов широко распространенных конструкций. Во многих случаях они не только позволяют кодить быстрее, но и выглядят понятнее и чище, чем длинные аналоги. В конце статьи приведен список современных возможностей языка, разделенный на версии. Переменные можно объявлять через запятую, при этом не требуется повторно использовать инструкцию Такой подход особенно удобен при объявлении нескольких переменных без моментального присваивания значений: Присваивание в JavaScript легко совмещается с арифметическими операторами: Если требуется присвоить значения сразу нескольким переменным, мы обычно делаем так: Но всю эту логику можно свести в одну строку, если использовать деструктуризацию: Синтаксис деструктуризации работает не только с массивами, но и с обычными объектами: Иногда требуется положить в переменную какое-то значение, предварительно убедившись, что это значение существует и не является falsy ( Для этого можно использовать обычную конструкцию Можно написать короче. Взять, например, логический оператор Еще более современный подход – nullish coalescing operator – Иногда требуется проверить, есть ли в переменной какое-либо значение. При этом важно учитывать и К счастью, нет необходимости проводить все проверки по отдельности, тем более, что при этом легко что-нибудь упустить. Например, 0, который в ряде ситуаций тоже может расцениваться как “пустое” значение. Можно просто положиться на JavaScript и его динамическую конверсию типов. Оператор В пункте Присваивание с дефолтным значением мы уже видели, как логический оператор ( Оператор Если Зачастую простые конструкции Таким образом можно преобразовать и более сложные условия, даже вложенные: Важно: чем сложнее условие, тем запутаннее выглядит тернарный оператор и предпочтительнее – стандартная конструкция Если требуется выполнить какие-то действия, когда Но чем больше таких “подходящих” значений, тем сильнее разрастается условие и тем проще сделать ошибку. Проще поместить все эти значения в массив и использовать метод Важно: метод Вместо того, чтобы рассматривать каждый случай внутри инструкции Всем знакомый старый-добрый цикл К счастью, в последних версиях языка появилось несколько более удобных альтернатив: Кроме того, есть замечательный функциональный метод Такой код выглядит очень понятно, но у него есть некоторые ограничения. Например, перебор массива методом Одиночный оператор сложения ( Избавиться от большого количества нулей поможет экспоненциальная запись: Если вы вдруг до сих пор не знали, то пришло время узнать – в JavaScript есть специальный оператор для возведения в степень: Двойное побитовое отрицание для 32-битных целых чисел дает такой же эффект, как Math.floor (округляет вниз): Строка – это по сути массив символов, поэтому к каждому из них можно обратиться по индексу: Чтобы соединить несколько одинаковых строк в одну, существует несколько подходов. Самый очевидный – и самый громоздкий – использовать цикл: Но есть и более логичный – встроенный метод Бонус для любителей нестандартных решений: Составление одной строки из нескольких фрагментов – ужасная головная боль. Нас спасут шаблонные литералы: Они не только позволяют избежать многочисленных конкатенаций, но и поддерживают многострочность. Обычно чтобы проверить, присутствует ли элемент в массиве, мы используем метод Но можно использовать другой подход, без сравнения индексов – побитовый оператор Оператор Важно: не жертвуйте читаемостью кода в угоду краткости. Используйте побитовые операторы только в том случае, если все члены вашей команды умеют с ними работать. Не стоит забывать и про удобнейший метод Метод Spread-синтаксис был введен в язык специально для облегчения множества операций со сложными структурами данных. Например, для конкатенации массивов: Или клонирования массива: Методы А можно воспользоваться деструктуризацией: Если имя свойства совпадает с именем переменной, в которой хранится значение, дублировать его необязательно: В современном JavaScript есть сразу 3 метода для перебора объектов: Трансформировав структуру данных таким образом, мы можем легко проитерировать как обычный массив любым удобным способом. Современный стандарт JavaScript позволяет задать дефолтные значения параметров прямо в сигнатуре функции. Теперь не нужно проверять это отдельно: Важно: дефолтное значение устанавливается только в том случае, если указанный параметр не передан или равен В операторе В ряде случаев стрелочные функции могут стать более короткой и удобной альтернативой обычным. Например, их очень удобно использовать для коллбэков: Стрелочные функции позволяют возвращать значение неявно, без использования оператора return: Важно: не злоупотребляйте стрелочными функциями из-за их краткости, используйте их по прямому назначению, например, для сохранения контекста выполнения. *** Сокращения в программировании похожи на лекарства. В небольших дозах они полезны и делают вашу жизнь лучше, но при передозировке возможно отравление и другие неприятные побочные эффекты. Поэтому соблюдайте меру и используйте сокращения только тогда, когда они действительно нужны и не нарушают читаемость кода. *** Объявление переменных и присваивание значений
1. Объявление нескольких переменных
let
:
// Длинно let test1 = 1; let test2 = 2; // Коротко let test1 = 1, test2 = 2;
let test1, test2, test3, test4, test5;
2. Арифметические операции
// Длинно test1 = test1 + 1; test2 = test2 - 1; test3 = test3 * 20; // Коротко test1++; test2--; test3 *= 20;
3. Присваивание значений нескольким переменным
let test1, test2, test3; test1 = 1; test2 = 2; test3 = 3;
let [test1, test2, test3] = [1, 2, 3];
const data = { test1: 1, test2: 2, test3: 3 }; // Длинно const test1 = data.test1; const test2 = data.test2; const test2 = data.test3; //shorthand const { test1, test2, test3 } = data;
4. Присваивание со значением по умолчанию
null
, undefined
, пустая строка, 0).if-else
:
let test2; if (test1) { test2 = test1; } else { test2 = 'default value'; }
||
. Если в переменной находится truthy-значение, то будет возвращено оно, иначе – дефолтное значение с правой стороны оператора.
let test 2 = test1 || 'default value';
??
. Однако он проверяет не на все falsy-значения, а только на null
и undefined
. В остальном логика такая же, как у оператора ||
.
const test = null ?? 'default value'; console.log(test); // 'default value' const test1 = 0 ?? 2; console.log(test1); // 0
Условия
5. Автоматическая проверка на truthy и falsy значения
null
, и undefined
, и другие falsy-значения (NaN
, пустая строка, 0).
if (test1 !== null || test1 !== undefined || test1 !== '') { // logic }
if (test1) { // logic }
if
самостоятельно приведет переменную к логическому значению и осуществит проверку.6. Логические операторы вместо if
||
) может заменить конструкцию if
.&&
также способен на многое:
// Длинно if (test1) { callMethod(); } // Коротко test1 && callMethod();
test1
является falsy-значением, то до инструкции callMethod()
выполнение не дойдет.7. Тернарный оператор вместо if
if-else
можно заменить еще более простым тернарным оператором:
// Длинно let test: boolean; if (x > 100) { test = true; } else { test = false; } // Коротко let test = (x > 10) ? true : false; // Еще короче let test = x > 10;
let x = 300, test2 = (x > 100) ? 'greater 100' : (x < 50) ? 'less 50' : 'between 50 and 100'; console.log(test2); // "greater than 100"
if-else
.8. Проверка на значение из набора
x
равен одному из нескольких значений, первым порывом может быть использование обычных сравнений:
if (x === 'abc' || x === 'def' || x === 'ghi' || x ==='jkl') { //logic }
Array.prototype.includes
для проверки:
if (['abc', 'def', 'ghi', 'jkl'].includes(x)) { //logic }
includes
использует строгое сравнение с учетом типа аргумента.9. Коллекция вместо switch
switch
, можно добавить их все в объект:
// Длинно switch (data) { case 1: test1(); break; case 2: test2(); break; case 3: test(); break; // ... } // Коротко const collection = { 1: test1, 2: test2, 3: test }; collection[data] && collection[data]();
Циклы
10. Короткий синтаксис for
for
имеет довольно громоздкую структуру:
for (var i = 0; i < testData.length; i++) { // i - индекс элемента // доступ к значению элемента i var item = testData[i]; }
for (let i in testData) { // i - индекс элемента // доступ к элементу i var item = testData[i]; } for (let i of testData) { // i - значение элемента }
forEach
:
function testData(element, index, array) { console.log('test[' + index + '] = ' + element); } [11, 24, 32].forEach(testData); // logs: test[0] = 11, test[1] = 24, test[2] = 32
forEach
нельзя прервать с помощью инструкции break
.Числа
11. Конверсия строки в число
+
) неявно приводит тип полученного аргумента к числу.
// Длинно let test1 = parseInt('123'); let test2 = parseFloat('12.3'); // Коротко let test1 = +'123'; let test2 = +'12.3';
12. Экспоненциальная запись
// Длинно for (var i = 0; i < 10000; i++) { ... } // Коротко for (var i = 0; i < 1e4; i++) { ... }
13. Возведение в степень
// Длинно Math.pow(2,3); // Коротко 2**3
14. Округление
// Длинно Math.floor(1.9) === 1 // true // Коротко ~~1.9 === 1 // true
Строки
15. Получение символа из строки
let str = 'abc'; // Длинно str.charAt(2); // c // Коротко str[2]; // c
16. Повторение строки
let test = ''; for(let i = 0; i < 5; i ++) { test += 'test '; }
String.prototype.repeat()
:
let test = 'test '.repeat(5);
let test = Array(6).join('test ');
17. Конкатенация
// Длинно const welcome = 'Hi ' + test1 + ' ' + test2 + '.' // Коротко const welcome = `Hi ${test1} ${test2}`;
// Длинно const data = 'abc abc abc abc abc abcnt' + 'test test,test test test testnt' // Коротко const data = `abc abc abc abc abc abc test test,test test test test`
Массивы
18. Наличие элемента
indexOf
и сравниваем найденный индекс с -1
.
if (arr.indexOf(item) > -1) { // элемент в массиве есть } if(arr.indexOf(item) === -1) { // элемента в массиве нет }
~
.
if(~arr.indexOf(item)) { // элемент в массиве есть } if(!~arr.indexOf(item)) { // элемента в массиве нет }
~
возвращает 0
только для значения -1
. Для всех других значений будет возвращено число, отличное от нуля, то есть truthy-значение.Array.prototype.includes
:
if (arr.includes(item)) { // элемент в массиве есть }
19. Поиск элемента
Array.prototype.find
– это удобная функциональная замена простому перебору элементов массива с помощью цикла for
:
// Длинно function findElementByName(arr, name) { for (let i = 0; i < arr.length; ++i) { if (arr[i].name === name) { return data[i]; } } } // Коротко function findElementByName(arr, name) { return arr.find(el => el.name === name); } const data = [ { name: 'John' }, { name: 'Jane' }, ] findElementByName('Jane'); // { name: 'Jane' }
20. Spread-синтаксис
// Стандартный подход const data = [1, 2, 3]; const test = [4, 5, 6].concat(data); // Spread-синтаксис const data = [1, 2, 3]; const test = [4, 5, 6, ...data]; console.log(test); // [ 4, 5, 6, 1, 2, 3]
// Стандартный подход const test1 = [1, 2, 3]; const test2 = test1.slice() // Spread-синтаксис const test1 = [1, 2, 3]; const test2 = [...test1];
21. Минимальное и максимальное значение
Math.max
и Math.min
могут принимать любое количество аргументов. Чтобы передать им массив, можно использовать метод Function.prototype.apply
:
const arr = [1,2,3]; Math.max.apply(null, arr); // 3 Math.min.apply(null, arr); // 1
Math.max(…arr); // 3 Math.min(…arr); // 1
Объекты
22. Присваивание значений
let test1 = 'a'; let test2 = 'b'; // Длинно let obj = {test1: test1, test2: test2}; // Коротко let obj = {test1, test2};
23. Перебор ключей и значений
Object.keys()
, Object.values()
и Object.entries()
. Каждый из них возвращает массив – ключей, значений или сразу и того, и другого.
const data = { test1: 'abc', test2: 'cde', test3: 'efg' }; Object.keys(data); // ['test1', 'test2', 'test3']; Object.values(data); // ['abc', 'cde', 'efg']; Object.entries(data); // [['test1','abc'],['test2','cde'],['test3','efg']]
Функции
24. Параметры по умолчанию
// Длинно function add(test1, test2) { if (test1 === undefined) test1 = 1; if (test2 === undefined) test2 = 2; return test1 + test2; } // Коротко function add(test1 = 1, test2 = 2) { return test1 + test2; } add(5, 10); // 15 add(5); // 7 add(); // 3 add(5, null); // 5
undefined
. На null
это не распространяется. 25. Операции в return
return
можно производить разнообразные вычисления, что позволит сэкономить пару строк кода.
// Длинно function check(test) { if (!test) { return 'default value'; } else { return test; } } // Коротко function check(test) { return test || 'default value'; }
26. Стрелочные функции
// Длинно [1, 2, 3].map(function(i) { return i * 2; }); // Коротко [1, 2, 3].map(i => i * 2);
// Длинно function calculate(diameter) { return Math.PI * diameter } // Коротко calculate = diameter => Math.PI * diameter;
Современные возможности JavaScript
ES2021/ES12
ES2020/ES11
ES2019/ES10
ES2018/ES9
s
в регулярных выражениях: режим dotall – точка может соответствовать символу переноса строки.ES2017/ES8
ES2016/ES7
- 4 views
- 0 Comment
Свежие комментарии