Массивы являются одной из самых популярных структур данных в JavaScript, потому что они используются для хранения данных. Кроме этого, массивы дают много возможностей для работы с этими самыми данными. Понимая, что для тех, кто находится в начале пути изучения JavaScript, массивы являются одной из самых основных тем, в этой статье я хотел бы познакомить вас с некоторыми полезными трюками, о которых вы могли не знать. Давайте начнем.

1. Как в массиве оставить только уникальные значения


Это очень популярный вопрос во время интервью на позицию Javascript-разработчика. Вот быстрое и простое решение этой задачки. Для начала вам нужно получить уникальные значения массива, для этого можно использовать new Set() (прим. перев.: структура данных Set хранит только уникальные значения). Далее нужно преобразовать структуру данных Set в массив. Я хочу познакомить вас с двумя способами, как это можно сделать: первый – с помощью метода from(), второй – с помощью оператора spread ("…").

const fruits = ['banana', 'apple', 'orange', 'watermelon', 'apple', 'orange', 'grape', 'apple'];

// Первый метод
const uniqueFruits = Array.from(new Set(fruits));
console.log(uniqueFruits); // вернет ['banana', 'apple', 'orange', 'watermelon', 'grape']

// Второй метод
const uniqueFruits2 = [...new Set(fruits)];
console.log(uniqueFruits2); // вернет ['banana', 'apple', 'orange', 'watermelon', 'grape']

Легко, правда?

2. Как заменить значения в массиве


Бывают такие ситуации, когда нужно заменить значения в массиве другими значениями. Для этого существует хороший метод, о котором вы, возможно, не знали – метод splice(start, value to remove, values to add), где start – номер индекса, начиная с которого мы хотим удалить элементы массива, value to remove – число элементов, которые мы хотим удалить, а values to add – элементы, которые мы хотим вставить на место удаленных:

const fruits = ['banana', 'apple', 'orange', 'watermelon', 'apple', 'orange', 'grape', 'apple'];
fruits.splice(0, 2, 'potato', 'tomato');
console.log(fruits); // вернет ["potato", "tomato", "orange", "watermelon", "apple", "orange", "grape", "apple"]

3. Как трансформировать массив, не используя метод map()


Наверное, все знают метод массива map(), но есть и другое решение, которое может быть использовано для получения аналогичного эффекта и чистого кода. Для этого мы можем воспользоваться методом from():

const friends = [
    { name: 'John', age: 22 },
    { name: 'Peter', age: 23 },
    { name: 'Mark', age: 24 },
    { name: 'Maria', age: 22 },
    { name: 'Monica', age: 21 },
    { name: 'Martha', age: 19 },
]

const friendsNames = Array.from(friends, ({name}) => name);
console.log(friendsNames); // вернет ['John', 'Peter', 'Mark', 'Maria', 'Monica', 'Martha']

4. Как быстро очистить массив


Например, у нас есть массив, в котором много элементов. Нам нужно его очистить (неважно для какой цели), при этом мы не хотим удалять элементы один за другим. Это очень просто сделать одной строчкой кода. Чтобы очистить массив, нам нужно установить длину массива в 0, и всё!

const fruits = ['banana', 'apple', 'orange', 'watermelon', 'apple', 'orange', 'grape', 'apple'];
fruits.length = 0;
console.log(fruits); // вернет []

5. Как преобразовать массив в объект


Бывает такая ситуация: у нас есть массив, но нам нужен объект (опять неважно для какой цели) с этими данными, и самый быстрый способ преобразовать массив в объект – это использовать оператор spread ("..."):

const fruits = ['banana', 'apple', 'orange', 'watermelon', 'apple', 'orange', 'grape', 'apple'];
const fruitsObj = { ...fruits };
console.log(fruitsObj); // вернет {0: 'banana', 1: 'apple', 2: 'orange', 3: 'watermelon', 4: 'apple', 5: 'orange', 6: 'grape', 7: 'apple'}

6. Как заполнить массив одинаковыми значениями


Бывают разные ситуации, когда мы хотим создать массив и заполнить его некоторыми значениями, или нам нужен массив с одинаковыми значениями. Метод fill() для подобных задач является отличным решением:

const newArray = new Array(10).fill('1');
console.log(newArray); // вернет ["1", "1", "1", "1", "1", "1", "1", "1", "1", "1"]

7. Как объединить более двух массивов


Вы знаете, как объединить массивы в один, не используя метод concat()? Существует простой способ объединить любое количество массивов в один массив одной строчкой кода. Как вы, вероятно, уже поняли, оператор spread ("...") является довольно полезным инструментом при работе с массивами, как и в этом случае:

const fruits = ['apple', 'banana', 'orange'];
const meat = ['poultry', 'beef', 'fish'];
const vegetables = ['potato', 'tomato', 'cucumber'];
const food = [...fruits, ...meat, ...vegetables];
console.log(food); // вернет ["apple", "banana", "orange", "poultry", "beef", "fish", "potato", "tomato", "cucumber"]

8. Как найти пересечение двух массивов


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

const numOne = [0, 2, 4, 6, 8, 8];
const numTwo = [1, 2, 3, 4, 5, 6];
const duplicatedValues = [...new Set(numOne)].filter(item => numTwo.includes(item));
console.log(duplicatedValues); // вернет [2, 4, 6]

9. Как удалить ложные значения из массива


Для начала, давайте определим ложные значения. В Javascript ложными значениями являются: false, 0, "", null, NaN и undefined. Теперь мы можем выяснить, как удалить такие значения из нашего массива. Для достижения этой цели нам потребуется метод filter():

const mixedArr = [0, 'blue', '', NaN, 9, true, undefined, 'white', false];
const trueArr = mixedArr.filter(Boolean);
console.log(trueArr); // вернет ["blue", 9, true, "white"]

10. Как получить рандомное значение массива


Иногда нам нужно выбрать рандомное значение массива. Чтобы решение было простым, коротким и быстрым, мы можем получить случайный номер индекса в соответствии с длиной массива. Посмотрите на этот пример:

const colors = ['blue', 'white', 'green', 'navy', 'pink', 'purple', 'orange', 'yellow', 'black', 'brown'];
const randomColor = colors[(Math.floor(Math.random() * (colors.length)))];
console.log(randomColor); // вернет рандомный цвет из массива

11. Как развернуть массив в обратную сторону


Когда нам нужно «перевернуть» наш массив, нет необходимости создавать его через сложные циклы и функции, потому что есть простой метод массива reverse(), который делает все это за нас, и одной строчкой кода мы можем «перевернуть» наш массив:

const colors = ['blue', 'white', 'green', 'navy', 'pink', 'purple', 'orange', 'yellow', 'black', 'brown'];
const reversedColors = colors.reverse();
console.log(reversedColors); // вернет ["brown", "black", "yellow", "orange", "purple", "pink", "navy", "green", "white", "blue"]

12. Метод lastIndexOf()


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

const nums = [1, 5, 2, 6, 3, 5, 2, 3, 6, 5, 2, 7];
const lastIndex = nums.lastIndexOf(5);
console.log(lastIndex); // вернет 9

13. Как просуммировать все значения в массиве


Еще один популярный вопрос во время собеседования на позицию JavaScript-разработчика. Сумму всех элементов можно найти одной строчкой кода, если знать метод reduce():

const nums = [1, 5, 2, 6];
const sum = nums.reduce((x, y) => x + y);
console.log(sum); // вернет 14

Заключение


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

Приятного написания кода!

Комментарии (40)


  1. andres_kovalev
    15.11.2019 21:10

    Помимо того, что почти половина "трюков" заключается в использовании стандартных и вполне себе известных методов массивов вроде reverse() и splice(), статья ещё и вводит некоторые сомнительные ограничения вроде — как трансформировать массив без map(). Зачем? Какое у from() преимущество, кроме менее лаконичной записи? Чем не угодили concat(), который работает быстрее спреда и для более чем двух массивов опять же позволяет получить более короткую запись?)


    1. gaiazovr Автор
      15.11.2019 23:32
      -1

      Перечитайте первый абзац еще раз. Эта статья рассчитана на новичков в программировании, которые, возможно, еще не знают все стандартные и известные методы. Да и метка стоит «beginners». Я не автор, я просто перевел ее)


      1. faiwer
        17.11.2019 22:52

        Зря вы выбрали именно эту статью. Скажем там в одном из примеров O(n^2) там где хватит O(n). Зачем такому учить новичков? Метод .reduce описан чуть менее чем никак, просто "магия". Вообще не упомянуто про то, что .reverse и .sort мутируют массив (и даже даётся ложная иллюзия того, что это не так, за счёт присваивания значения новой переменной). Вообще статья попахивает, если честно.


        1. gaiazovr Автор
          18.11.2019 20:13

          Согласен с Вами. Надо ответственнее подходить к выбору статьи для переводов, я это понял на своем опыте)


    1. vintage
      16.11.2019 12:50
      +1

      Зачем? Какое у from() преимущество, кроме менее лаконичной записи?

      Он работает с итерируемыми обектами, не являющимися массивами и соответственно не имеющими метода map. Например DOM API возвращает всё что угодно, но не массивы, к сожалению.


      1. andres_kovalev
        16.11.2019 14:18

        Вы правы. Жаль только это в комментариях, а не в статье)


      1. Zenitchik
        17.11.2019 00:20

        Он работает с итерируемыми обектами

        Не только с итерируемыми, но и с массивоподобными. Например {length:3}


  1. Aingis
    15.11.2019 21:27

    Ожидание: 13 полезных приёмов.
    Реальность:

    3. Как трансформировать массив, не используя метод map()
    5. Как преобразовать массив в объект
    12. Метод lastIndexOf()
    Причём только 10-й пункт ушёл лишь чуточку дальше использования примеров из документации.


  1. Zenitchik
    15.11.2019 21:54
    +3

    const numOne = [0, 2, 4, 6, 8, 8];
    const numTwo = [1, 2, 3, 4, 5, 6];
    const duplicatedValues = [...new Set(numOne)].filter(item => numTwo.includes(item));
    console.log(duplicatedValues); // вернет [2, 4, 6]


    Автор охренел? Нахрена было создавать набор, если потом всё равно проверяем includes в массиве?

    const numOne = [0, 2, 4, 6, 8, 8];
    const numTwo = [1, 2, 3, 4, 5, 6];
    const mySet = new Set(numOne);
    const duplicatedValues = numTwo.filter(value => mySet.has(item));
    


    1. yarick123
      15.11.2019 22:59
      +1

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

      const numOne = [0, 2, 4, 6, 8, 8];
      const numTwo = [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1];
      

      заполнит duplicatedValues так: [ 2, 4, 6, 4, 2 ]
      Вариант с двумя наборами:
      const numOne = [0, 2, 4, 6, 8, 8];
      const numTwo = [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1];
      const mySet = new Set(numOne);
      const duplicatedValues = [...new Set(numTwo.filter(item => mySet.has(item)))];
      console.log(duplicatedValues); // вернет [2, 4, 6]
      

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


      1. Zenitchik
        15.11.2019 23:10
        +1

        В условии не было сказано, что результат не должен содержать повторов.


        1. yarick123
          15.11.2019 23:27
          -1

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


          1. igormich88
            16.11.2019 00:07

            В оригинале написано «Find the intersection of two arrays». И в этом случае, операция пересечения множеств коммутативна. Зачем было переводить как «Как найти общие элементы двух массивов» непонятно.


            1. gaiazovr Автор
              16.11.2019 09:01

              Это мой косяк, спасибо за замечание, поправлю. Я посчитал, что «общие элементы» звучит понятнее, чем «пересечение». Но в итоге получился немного другой смысл.


    1. dom1n1k
      16.11.2019 01:29

      Я на полминуты завис от слова «набор». Множество же.


  1. DollaR84
    15.11.2019 23:06

    прошу прощения за нубский вопрос, я не спец в JavaScript. Хотел спросить по поводу объектов. Таки в JavaScript словарь называется объектом, или это особенности перевода?


    1. Zenitchik
      15.11.2019 23:12
      +1

      Простите, какой язык Вам родной? Просто не вполне понятно, что Вы называете словарём.


      1. DollaR84
        15.11.2019 23:16

        python.
        А словарем я называю то, что получают в 5 совете:
        {0: 'banana', 1: 'apple', 2: 'orange', 3: 'watermelon', 4: 'apple', 5: 'orange', 6: 'grape', 7: 'apple'}


        1. Zenitchik
          15.11.2019 23:21
          +1

          Ну, если пользоваться терминологией питона и сильно упрощать, то можно сказать, что в JS любой объект — словарь. При этом объектом, в смысле ООП он быть не перестаёт.


          1. DollaR84
            15.11.2019 23:26

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


          1. yarick123
            15.11.2019 23:46
            +1

            Добавлю, что объект в JavaScript похож на «классический » словарь (std::map в c++) методами доступа к полям (в JavaScript они называются свойствами — properties), но всё-же словарём не является. Есть ограничения/тонкости. Хотя, до появления Map, объекты часто использовались в качестве словарей с известными ограничениями.


            1. DollaR84
              16.11.2019 00:30

              да, аналогию с map понял, спасибо. Все равно хотел когда-то начать знакомиться с JS, видимо пора начать :)


            1. Videoman
              16.11.2019 01:00

              Скорее всего вы имели в виду std::unordered_map


        1. printf
          15.11.2019 23:56
          +1

          Объекты в жс это в первом приближении словари, да. Причем ключи всегда строки:

          const a = {1.0: 2.0}
          Object.keys(a) // [ "1" ]
          

          Впрочем, есть и хорошие человеческие словари.


          1. DollaR84
            16.11.2019 00:32

            да, интересно автоматическое приведение типа, ох… Спасибо, почитаю подробнее


  1. yarick123
    15.11.2019 23:54
    +2

    В пятом совете в итоге получится объект

    { '0': 'banana', '1': 'apple', '2': 'orange', '3': 'watermelon', '4': 'apple', '5': 'orange', '6': 'grape', '7': 'apple' }
    . То-есть, числовые ключи преобразуются в строки. Кстати, в оригинале та же неточность.


    1. DollaR84
      16.11.2019 00:38

      да, по ответу printf понял, что ключи приводятся к строке, я копировал пример из статьи


  1. Psychosynthesis
    16.11.2019 02:20

    4. Чем это отличается от arr = []? Вообще не представляю нафига усложнять этот пример до написания лишнего lenght.
    5 и 8 — это спасибо спреду скажите, лучше бы пример на ES5 дали.
    А, ну и пример с использованием мат.рандом вообще банальность дикая, как по мне.

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


    1. Finesse
      16.11.2019 03:35

      4. Там массив изменяется по ссылке, а у вас нет


      1. Psychosynthesis
        17.11.2019 21:44
        -2

        Какая мне разница что там изменится по ссылке, если меня волнует, в первую очередь, на что указывает указатель?


        1. faiwer
          17.11.2019 22:57

          It depends. Зависит от задачи. Если на ваш массив уже есть где-то другие ссылки, и вы желаете чтобы они всё также вели на актуальный набор данных, то вам очень даже важно ничего не поломать.


          1. Psychosynthesis
            18.11.2019 11:53

            Если на мой массив где-то есть другие ссылки, с какой целью мне понадобится делать ему lenght = 0 и сохранять при этом содержимое?

            Приведите не синтетический пример.


            1. faiwer
              18.11.2019 12:16
              -1

              с какой целью мне понадобится делать ему lenght = 0

              дабы обеспечить консистентность данных при обнулении коллекции.


              Приведите не синтетический пример

              Вы же пишете, что у вас 10+ лет опыта в программировании. Это такой троллинг?


              1. Psychosynthesis
                18.11.2019 19:14

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

                Это такой троллинг?

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


                1. faiwer
                  18.11.2019 21:01

                  Хорошо, на этом и порешим.


    1. gaiazovr Автор
      16.11.2019 09:26

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


  1. rmuskovets
    16.11.2019 10:31

    А как оставить те, что НЕ уникальные?)


  1. ganqqwerty
    16.11.2019 10:35

    Дружище, ну хоть вычитай то, что написал. Как «пере» массив, как полуь массив, это же позор.


    1. gaiazovr Автор
      16.11.2019 11:29

      Спасибо за замечание :) Я использую гугл-расширение Multi-higlight, которое подсвечивает внесенные в список слова. В этом списке в том числе есть слова «вам», «чит», «вернуть», «очен». И похоже из-за этого расширения при редактировании статьи подсвеченные слова были выброшены из текста. В общем, нашелся интересный баг)


  1. Legomegger
    18.11.2019 12:17

    воистину функциональщина топ