11 (и более!) функций JavaScript, которые необходимо знать

Код умный! Станьте более быстрым, продуктивным и счастливым разработчиком JavaScript, освоив эти наиболее важные и повторяющиеся функции языка.

Будь то бэкэнд или интерфейс (или даже космические корабли), JavaScript повсюду. Кроме того, это довольно гибкий язык (это означает, что в нем есть сложные шаблоны функционального программирования, а также старые добрые классы), а его сходство с другими «C-подобными» языками облегчает переход разработчиков с других языков.

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

карта()

Было бы ересью написать статью о важных функциях JavaScript и не упомянуть map()! 😆😆 Наряду с filter() и reduce(), map() образует своего рода святую троицу. Это функции, которые вы будете использовать снова и снова в своей карьере, поэтому они более чем заслуживают внимания. Давайте рассмотрим их один за другим, начиная с map().

map() — одна из тех функций, которые доставляют больше всего проблем людям, изучающим JavaScript. Почему? Не потому, что в ней есть что-то сложное по своей сути, а потому, что принцип работы этой функции — идея, взятая из так называемого функционального программирования. И поскольку мы не знакомимся с функциональным программированием — наши школы и индустрия полны объектно-ориентированных языков — работа кажется странной или даже неправильной для нашего предвзятого мозга.

JavaScript гораздо более функционален, чем объектно-ориентированный, хотя его современные версии делают все возможное, чтобы скрыть этот факт. Но это целая банка червей, которую я смогу открыть, возможно, когда-нибудь. 🤣 Итак, map() . . .

map() — очень простая функция; он присоединяется к массиву и помогает нам преобразовать каждый элемент во что-то другое, в результате чего получается новый массив. Как именно преобразовать элемент, предоставляется в виде другой функции, которая по соглашению является анонимной.

Вот и все! К синтаксису может потребоваться некоторое время, чтобы привыкнуть, но по сути это то, что мы делаем в функции map(). Почему мы можем захотеть использовать map()? Зависит от того, чего мы пытаемся достичь. Например, предположим, что мы записали температуру для каждого дня последней недели и сохранили ее в виде простого массива. Однако теперь нам говорят, что приборы были не очень точными и показали температуру на 1,5 градуса ниже, чем должны были.

Мы можем сделать эту коррекцию с помощью функции map() следующим образом:

const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];

const correctedWeeklyReadings = weeklyReadings.map(reading => reading + 1.5);

console.log(correctedWeeklyReadings); // gives [ 21.5, 23.5, 22, 20.5, 22.5, 23, 24.5 ]

Другой, очень практичный пример, взят из мира React, где создание списков элементов DOM из массивов является распространенным шаблоном; так, что-то вроде этого распространено:

export default ({ products }) => {
    return products.map(product => {
        return (
            <div className="product" key={product.id}>
                <div className="p-name">{product.name}</div>
                <div className="p-desc">{product.description}</div>
            </div>
        );
    });
};

Здесь у нас есть функциональный компонент React, который получает список продуктов в качестве реквизита. Затем из этого списка (массива) создается список HTML-элементов div, по существу преобразующий каждый объект продукта в HTML. Исходный объект продуктов остается нетронутым.

Вы можете возразить, что map() — это не что иное, как прославленный цикл for, и вы будете совершенно правы. Но заметьте, что как только вы выдвигаете этот аргумент, начинает говорить ваш натренированный объектно-ориентированный ум, в то время как эти функции и их обоснование исходят из функционального программирования, где высоко ценятся единообразие, компактность и элегантность. 🙂

фильтр()

filter() — очень полезная функция, которую вы будете применять снова и снова во многих ситуациях. Как следует из названия, эта функция фильтрует массив на основе заданных вами правил/логики и возвращает новый массив, содержащий элементы, удовлетворяющие этим правилам.

Давайте повторно используем наш пример с погодой. Предположим, что у нас есть массив, содержащий максимальные температуры для каждого дня прошлой недели; Теперь мы хотим узнать, сколько из этих дней было холоднее. Да, «холоднее» — это субъективный термин, поэтому, скажем, мы ищем дни, когда температура была ниже 20. Мы можем сделать это с помощью функции filter() следующим образом:

const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];

const colderDays = weeklyReadings.filter(dayTemperature => {
    return dayTemperature < 20;
});

console.log("Total colder days in week were: " + colderDays.length); // 1

Обратите внимание, что анонимная функция, которую мы передаем в filter(), должна возвращать логическое значение: true или false. Вот как filter() узнает, следует ли включать этот элемент в отфильтрованный массив. Вы можете написать любую сложную логику внутри этой анонимной функции; вы можете совершать вызовы API и читать вводимые пользователем данные и т. д., если вы убедитесь, что в конце концов вы возвращаете логическое значение.

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

const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];

const colderDays = weeklyReadings.filter(dayTemperature => {
    return dayTemperature < 20;
});

if(colderDays) {
    console.log("Yes, there were colder days last week");
} else {
    console.log("No, there were no colder days");
}

Заметил что-то? Отличная работа, если вы это сделали! Условие if ближе к концу проверяет colderDays, который на самом деле является массивом! Вы удивитесь, сколько раз люди совершают эту ошибку, стремясь уложиться в сроки или кодируя в плохом настроении (по какой-то причине). Проблема с этим условием заключается в том, что JavaScript — странный и непоследовательный язык во многих отношениях, и «правдивость» вещей — один из них. Пока [] == true возвращает false, заставляя вас думать, что приведенный выше код не нарушен, реальность такова, что внутри условия if, [] оценивается как истина! Другими словами, написанный нами код никогда не скажет, что на прошлой неделе не было более холодных дней.

Исправление очень простое, как указано в коде перед приведенным выше кодом. Мы проверяем значение colderDays.length, которое гарантированно дает нам целое число (ноль или больше) и, таким образом, последовательно работает при логических сравнениях. Обратите внимание, что filter() всегда, всегда, всегда будет возвращать массив, пустой или непустой, так что мы можем положиться на это и уверенно писать наши логические сравнения.

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

уменьшать()

Из всех функций в этой статье, а также в стандартной библиотеке JavaScript, функция reduce() является одной из первых претендентов на звание «запутанной и странной». Хотя эта функция очень важна и во многих ситуациях приводит к элегантному коду, большинство разработчиков JavaScript избегают ее и вместо этого предпочитают писать более подробный код.

Причина в том, что — и я буду честен здесь! — reduce() сложно понять как с точки зрения концепции, так и с точки зрения исполнения. Когда вы читаете его описание, вы перечитывали его несколько раз и до сих пор сомневаетесь в себе, правильно ли вы его прочитали; и когда вы видите его в действии и пытаетесь визуализировать, как он работает, ваш мозг скручивается на тысячу узлов! 🤭

Не пугайтесь. Функция reduce() и близко не уступает по сложности и запугиванию, скажем, Б+ Деревья и их алгоритмы. Просто подобная логика редко встречается в повседневной работе обычного программиста.

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

Как следует из названия, функция reduce() используется, чтобы что-то уменьшить. То, что он уменьшает, — это массив, а то, к чему он уменьшает данный массив, — это одно значение (число, строка, функция, объект, что угодно). Вот более простой способ выразить это — reduce() преобразует массив в одно значение. Обратите внимание, что возвращаемое значение из функции reduce() не является массивом, как в случае с map() и filter(). Понять это уже полдела. 🙂

Теперь очевидно, что если мы собираемся преобразовать (уменьшить) массив, нам нужно предоставить необходимую логику; и, основываясь на вашем опыте разработчика JS, вы, скорее всего, уже догадались, что мы делаем это с помощью функции. Эту функцию мы называем функцией редуктора, которая формирует первый аргумент функции reduce(). Второй аргумент — это начальное значение, такое как число, строка и т. д. (чуть позже я объясню, что это за «начальное значение»).

Основываясь на нашем понимании, мы можем сказать, что вызов функции reduce() выглядит следующим образом: array.reduce(reducerFunction, startValue). Теперь давайте займемся сердцем всего этого: функцией редуктора. Как уже было сказано, функция редуктора — это то, что сообщает методу reduce(), как преобразовать массив в одно значение. Он принимает два аргумента: переменная, которая действует как аккумулятор (не волнуйтесь, я объясню и этот момент), и переменная для хранения текущего значения.

Я знаю я знаю . . . это было много терминологии для одной функции, которая даже не является обязательной в JavaScript. 😝😝 И именно поэтому люди убегают от метода reduce(). Но если вы будете изучать его шаг за шагом, вы не только поймете его, но и оцените по мере того, как станете лучшим разработчиком.

Итак, вернемся к обсуждаемой теме. «Начальное значение», передаваемое в reduce(), равно . . . ну, начальное значение для расчета, который вы хотите использовать. Например, если вы собираетесь выполнять умножение в функции редуктора, начальное значение 1 имеет смысл; для добавления вы можете начать с 0 и так далее.

Теперь давайте посмотрим на сигнатуру функции редуктора. Функция редуктора, передаваемая в метод reduce(), имеет следующий вид: reducerFunction(accumulator, currentValue). «Аккумулятор» — это просто причудливое название переменной, которая собирает и хранит результат вычисления; это точно так же, как использовать переменную с именем total для суммирования всех элементов в массиве, используя что-то вроде total += arr[i]. Именно так применяется функция редюсера в reduce(): первоначально в аккумулятор устанавливается начальное значение, которое вы указали, а затем один за другим посещаются элементы массива, выполняются вычисления, и результат сохраняется в аккумулятор и так далее. . .

Итак, что это за «текущее значение» в функции-редукторе? Это та же самая идея, которую вы мысленно представили бы, если бы я попросил вас пройтись по массиву: вы берете переменную, начиная с нулевого индекса, и перемещаете ее вперед на шаг за раз. Пока вы это делаете, если я попрошу вас внезапно остановиться, вы окажетесь на одном из элементов массива, верно? Вот что мы подразумеваем под текущим значением: это значение переменной, используемой для представления рассматриваемого в данный момент элемента массива (подумайте о переборе массива, если это поможет).

После всего сказанного пришло время рассмотреть простой пример и посмотреть, как весь этот жаргон объединяется в реальном вызове reduce(). Допустим, у нас есть массив, содержащий первые n натуральных чисел (1, 2, 3… n), и нам нужно найти факториал n. Мы знаем, что найти! нам просто нужно умножить все, что приводит нас к этой реализации:

const numbers = [1, 2, 3, 4, 5];
const factorial = numbers.reduce((acc, item) => acc * item, 1);
console.log(factorial); // 120

Многое происходит в этих трех строках кода, поэтому давайте раскроем их одну за другой в контексте (очень долгого) обсуждения, которое у нас было до сих пор. Очевидно, что numbers — это массив, содержащий все числа, которые мы хотим перемножить. Затем взгляните на вызов number.reduce(), в котором говорится, что начальное значение для acc должно быть 1 (поскольку оно не влияет на умножение и не уничтожает его). Затем проверьте тело функции редуктора, `(acc, item) => acc * item, которое просто говорит, что возвращаемое значение для каждой итерации по массиву должно быть этим элементом, умноженным на то, что уже находится в аккумуляторе. Итерация и фактическое явное сохранение умножения в аккумуляторе — это то, что происходит за кулисами, и это одна из главных причин, по которой метод reduce() является таким камнем преткновения для разработчиков JavaScript.

Зачем использовать сокращение()?

Это действительно отличный вопрос, и, честно говоря, у меня нет точного ответа. Что бы ни делала функция reduce(), это можно сделать с помощью циклов, forEach() и т. д. Однако эти методы приводят к гораздо большему объему кода, что затрудняет его чтение, особенно если вы спешите. Кроме того, существует проблема неизменности: с помощью функции reduce() и подобных функций вы можете быть уверены, что ваши исходные данные не были изменены; это само по себе устраняет целые классы ошибок, особенно в распределенных приложениях.

Наконец, метод reduce() намного более гибок в том смысле, что аккумулятором может быть объект, массив или даже функция, если это необходимо; то же самое относится к начальному значению и другим частям вызова функции — почти все может быть введено и почти все может быть получено, поэтому существует исключительная гибкость при разработке повторно используемого кода.

Если вы все еще не убеждены, это тоже совершенно нормально; само сообщество JavaScript резко разделилось по поводу «компактности», «элегантности» и «мощности» метода reduce(), так что ничего страшного, если вы его не используете. 🙂 Но обязательно посмотрите на некоторые аккуратные примеры прежде чем вы решите уменьшить ().

немного()

Допустим, у вас есть массив объектов, каждый из которых представляет человека. Вы хотите знать, есть ли в массиве люди старше 35 лет. Обратите внимание, что нет необходимости подсчитывать количество таких людей, не говоря уже о получении их списка. То, что мы говорим здесь, является эквивалентом «один или несколько» или «по крайней мере один».

Как ты это делаешь?

Да, вы можете создать переменную флага и перебрать массив, чтобы решить эту проблему следующим образом:

const persons = [
    {
        name: 'Person 1',
        age: 32
    },
    
    {
        name: 'Person 2',
        age: 40
    },
];

let foundOver35 = false;

for (let i = 0; i < persons.length; i ++) {
    if(persons[i].age > 35) {
        foundOver35 = true;
        break;
    }
}

if(foundOver35) {
    console.log("Yup, there are a few people here!")
}

Проблема? На мой взгляд, код слишком похож на C или Java. Еще одно слово, которое приходит на ум, — «многословный». Опытный JS может думать о «уродливом», «ужасном» и т. д. 😝 И правильно, я бы сказал. Один из способов улучшить этот фрагмент кода — использовать что-то вроде map(), но даже в этом случае решение немного неуклюжее.

Оказывается, у нас есть довольно изящная функция some(), уже доступная в основном языке. Эта функция работает с массивами и принимает пользовательскую функцию «фильтрации», возвращая логическое значение true или false. По сути, он делает то, что мы пытались сделать последние несколько минут, только очень лаконично и элегантно. Вот как мы можем его использовать:

const persons = [
    {
        name: 'Person 1',
        age: 32
    },
    
    {
        name: 'Person 2',
        age: 40
    },
];

if(persons.some(person => {
    return person.age > 35
})) {
    console.log("Found some people!")
}

Тот же ввод, тот же результат, что и раньше; но обратите внимание на значительное сокращение кода! Обратите также внимание на то, насколько резко снижается когнитивная нагрузка, потому что нам больше не нужно разбирать код построчно, как если бы мы сами были интерпретатором! Теперь код читается почти как естественный язык.

каждый()

Как и в случае с some(), у нас есть еще одна полезная функция, которая называется Every(). Как вы уже догадались, это тоже возвращает логическое значение в зависимости от того, все ли элементы в массиве проходят заданный тест. Конечно, тест на прохождение в большинстве случаев предоставляется как анонимная функция. Я избавлю вас от мучений по поводу того, как может выглядеть наивная версия кода, поэтому вот как используется every():

const entries = [
    {
        id: 1
    },
    
    {
        id: 2
    },
    
    {
        id: 3  
    },
];

if(entries.every(entry => {
    return Number.isInteger(entry.id) && entry.id > 0;
})) {
    console.log("All the entries have a valid id")
}

Как видно, код проверяет все объекты в массиве на допустимое свойство id. Определение «действительного» зависит от контекста задачи, но, как видите, для этого кода я рассматривал неотрицательные целые числа. Еще раз мы видим, насколько просто и элегантно читается код, что является единственной целью этой (и подобных) функций.

включает()

Как вы проверяете наличие подстрок и элементов массива? Что ж, если вы похожи на меня, вы быстро достигаете indexOf(), а затем просматриваете документы, чтобы узнать возможные возвращаемые значения. Это значительное неудобство, а возвращаемые значения трудно запомнить (быстро — что означает процесс, возвращающий операционной системе 2?).

Но есть хорошая альтернатива, которую мы можем использовать: include(). Использование так же просто, как и название, а получившийся код чрезвычайно греет сердце. Имейте в виду, что сопоставление, выполняемое с помощью include(), чувствительно к регистру, но я думаю, что мы все интуитивно ожидаем этого в любом случае. А теперь время для кода!

const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(4));
const name = "Ankush";
console.log(name.includes('ank')); // false, because first letter is in small caps
console.log(name.includes('Ank')); // true, as expected

Однако не ожидайте слишком многого от этого скромного метода:

const user = {a: 10, b: 20};
console.log(user.includes('a')); // blows up, as objects don't have a "includes" method

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

const persons = [{name: 'Phil'}, {name: 'Jane'}];
persons.includes({name: 'Phil'});

Итак, что происходит, когда вы запускаете этот код? Он не взрывается, но вывод тоже разочаровывает: false. 😫😫 На самом деле, это связано с объектами, указателями и тем, как JavaScript видит память и управляет ею, а это отдельный мир. Если вы хотите погрузиться глубже, не стесняйтесь сделать решительный шаг (возможно, начните здесь), но я остановлюсь прямо здесь.

Мы можем заставить приведенный выше код работать, если перепишем его следующим образом, но на данный момент, на мой взгляд, это более или менее становится шуткой:

const phil = {name: 'Phil'};
const persons = [phil, {name: 'Jane'}];
persons.includes(phil); // true

Тем не менее, это показывает, что мы можем заставить include() работать с объектами, так что я думаю, что это не полная катастрофа. 😄

ломтик()

Предположим, у нас есть строка, и я прошу вас вернуть ее часть, начинающуюся с «r» и заканчивающуюся на «z» (фактические символы не важны). Как бы вы подошли к этому? Возможно, вы бы создали новую строку и использовали ее для хранения всех необходимых символов и их возврата. Или, если вы похожи на большинство программистов, вы бы дали мне взамен два индекса массива: один указывает на начало подстроки, а другой — на конец.

Оба эти подхода хороши, но есть концепция, называемая нарезкой, которая предлагает аккуратное решение в таких ситуациях. К счастью, здесь нет заумной теории; нарезка означает именно то, на что это похоже — создание меньшей строки/массива из заданной, так же, как мы создаем кусочки фруктов. Давайте посмотрим, что я имею в виду, на простом примере:

const headline = "And in tonight's special, the guest we've all been waiting for!";
const startIndex = headline.indexOf('guest');
const endIndex = headline.indexOf('waiting');
const newHeadline = headline.slice(startIndex, endIndex);
console.log(newHeadline); // guest we've all been

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

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

Нарезка аккуратна и чрезвычайно удобна, и нет причин не использовать ее. Это также не синтаксический сахар, пронизанный штрафом за производительность, поскольку он создает неглубокие копии исходного массива/строки. Я настоятельно рекомендую разработчикам JavaScript ознакомиться с функцией slice() и добавить ее в свой арсенал!

соединение ()

Метод splice() звучит как двоюродный брат slice(), и в некотором смысле мы можем утверждать, что это так. Оба создают новые массивы/строки из исходных, с одним небольшим, но важным отличием — splice() удаляет, изменяет или добавляет элементы, но модифицирует исходный массив. Это «разрушение» исходного массива может создать огромные проблемы, если вы не будете осторожны или не понимаете глубоких копий и ссылок. Интересно, что мешало разработчикам использовать тот же подход, что и для slice(), и оставить исходный массив нетронутым, но я думаю, что мы можем быть более снисходительными к языку создан всего за десять дней.

Несмотря на мои жалобы, давайте посмотрим, как работает splice(). Я покажу пример, в котором мы удаляем несколько элементов из массива, так как это наиболее распространенное использование этого метода. Я также воздержусь от примеров сложения и вставки, потому что их легко найти, и они также просты.

const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
items.splice(2, 1);
console.log(items); // [ 'eggs', 'milk', 'bread', 'butter' ]

Приведенный выше вызов splice() говорит: начните с индекса 2 (то есть с третьего места) массива и удалите один элемент. В данном массиве «сыр» является третьим элементом, поэтому он удаляется из массива, а массив элементов сокращается, как и ожидалось. Кстати, удаленные элементы возвращаются функцией splice() в форме или массиве, поэтому, если бы мы захотели, мы могли бы зафиксировать «сыр» в переменной.

По моему опыту, indexOf() и splice() отлично сочетаются друг с другом — мы находим индекс элемента, а затем удаляем его из заданного массива. Однако обратите внимание, что это не всегда самый эффективный метод, и часто использование ключей объекта (эквивалент хэш-карты) намного быстрее.

сдвиг()

shift() — это своего рода метод удобства, который используется для удаления первого элемента массива. Обратите внимание, что то же самое можно сделать с помощью splice(), но shift() немного легче запомнить и интуитивно понятен, когда все, что вам нужно сделать, это отрезать первый элемент.

const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
items.shift()
console.log(items); // [ 'milk', 'cheese', 'bread', 'butter' ]

отменить сдвиг ()

Точно так же, как shift() удаляет первый элемент из массива, unshift() добавляет новый элемент в начало массива. Его использование такое же простое и компактное:

const items = ['eggs', 'milk'];
items.unshift('bread')
console.log(items); // [ 'bread', 'eggs', 'milk' ]

Тем не менее, я не могу с собой поделать и предостерегаю новичков в игре: в отличие от популярных методов push() и pop(), shift() и unshift() крайне неэффективны (из-за того, как работают лежащие в их основе алгоритмы). Таким образом, если вы работаете с большими массивами (скажем, более 2000 элементов), слишком большое количество вызовов этих функций может привести к остановке вашего приложения.

наполнять()

Иногда вам нужно изменить несколько элементов на одно значение или даже, так сказать, «сбросить» весь массив. В таких ситуациях fill() спасает вас от циклов и ошибок, возникающих при переходе от одного к другому. Его можно использовать для замены части или всего массива заданным значением. Давайте посмотрим на пару примеров:

const heights = [1, 2, 4, 5, 6, 7, 1, 1];
heights.fill(0);
console.log(heights); // [0, 0, 0, 0, 0, 0, 0, 0]

const heights2 = [1, 2, 4, 5, 6, 7, 1, 1];
heights2.fill(0, 4);
console.log(heights2); // [1, 2, 4, 5, 0, 0, 0, 0]

Другие функции, о которых стоит упомянуть

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

  • задний ход()
  • Сортировать()
  • записи()
  • наполнять()
  • найти()
  • плоский()

Я призываю вас, по крайней мере, просмотреть их, чтобы иметь некоторое представление о том, что такие удобства существуют.

Вывод

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

Всякий раз, когда вы можете, потратьте некоторое время на изучение основного языка (и, если возможно, известных служебных библиотек, таких как Лодаш). Даже несколько минут, потраченных на это усилие, приведут к значительному повышению производительности, а код станет намного чище и компактнее.