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



Здесь представлено 13 однострочников. Примеры подготовлены с использованием Node.js v11.x. Если вы будете использовать их в другой среде — это может повлиять на их выполнение.

1. Приведение значений к логическому типу


Вот как привести некое значение к логическому типу:

const myBoolean = !!myVariable;

Двойное отрицание (!!) нужно для того, чтобы значение, являющееся с точки зрения правил JavaScript истинным, было бы преобразовано в true, а ложным — в false.

2. Избавление от повторяющихся значений в массивах


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

const deDupe = [...new Set(myArray)];

Структуры данных типа Set хранят лишь уникальные значения. В результате использование такой структуры данных и синтаксиса spread позволяет создать на основе массива myArray новый массив, в котором нет повторяющихся значений.

3. Создание и установка свойств объектов по условию


Для того чтобы задавать свойства объектов с использованием оператора &&, можно воспользоваться синтаксисом spread:

const myObject = { ...myProperty && { propName: myProperty } };

Если в результате вычисления левой части выражения будет получено нечто, воспринимаемое JS как ложное значение, то && не будет проводить дальнейшие вычисления и новое свойство не будет создано и установлено. Объект myObject будет пустым. Если же конструкция ...myProperty вернёт какой-то результат, воспринимаемый JS как истинный, благодаря конструкции && в объекте появится свойство propName, хранящее полученное значение.

4. Слияние объектов


Вот как можно создать новый объект, в котором будут скомбинированы два других объекта:

const mergedObject = { ...objectOne, ...objectTwo };

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

5. Обмен значений переменных


Для того чтобы обменять значения между двумя переменными без использования вспомогательной переменной можно поступить так:

[varA, varB] = [varB, varA];

После этого то, что было в varA, попадёт в varB, и наоборот. Это возможно благодаря использованию внутренних механизмов деструктурирования.

6. Удаление ложных значений из массива


Вот как можно убрать из массива все значения, которые считаются в JavaScript ложными:

const clean = dirty.filter(Boolean);

В ходе выполнения этой операции из массива будут удалены такие значения, как null, undefined, false, 0, а так же пустые строки.

7. Преобразование чисел в строки


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

const stringArray = numberArray.map(String);

Строковые элементы массива в ходе подобного преобразования так и останутся строковыми.

Можно выполнить и обратное преобразование — преобразовав значения типа String к значениям типа Number:

const numberArray = stringArray.map(Number);

8. Извлечение значений свойств объектов


Вот как можно извлечь значение свойства объекта и записать его в константу, имя которой отличается от имени этого свойства:

const { original: newName } = myObject;

Благодаря использованию этой конструкции будет создана новая константа, newName, в которую будет записано значение свойства original объекта myObject.

9. Форматирование JSON-кода


Вот как можно преобразовать JSON-код к виду, удобному для восприятия:

const formatted = JSON.stringify(myObj, null, 2);

Метод stringify принимает три параметра. Первый — это JavaScript-объект. Второй, необязательный, представляет собой функцию, которую можно использовать для обработки JSON-кода, получающегося в ходе преобразования объекта. Последний параметр указывает на то, сколько пробелов нужно использовать при формировании отступов в JSON-коде. Если опустить последний параметр, то весь полученный JSON-код будет представлять собой одну длинную строку. Если в объекте myObj есть циклические ссылки, преобразовать его в формат JSON не удастся.

10. Быстрое создание числовых массивов


Вот как можно создать массив и заполнить его числами:

const numArray = Array.from(new Array(52), (x, i) => i);

Первый элемент такого массива имеет индекс 0. Размер массива можно задавать как с помощью числового литерала, так и с помощью переменной. Здесь мы создаём массив из 52 элементов, который, например, можно использовать для хранения данных о колоде карт.

11. Создание кодов для двухфакторной аутентификации


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

const code = Math.floor(Math.random() * 1000000).toString().padStart(6, "0");

Обратите внимание на то, что количество нулей в числе, на которое умножается результат, возвращаемый Math.random(), должно соответствовать первому параметру (targetLength) метода padStart.

12. Перемешивание массива


Для того чтобы перемешать массив, не зная при этом о том, что именно в нём содержится, можно сделать так:

myArray.sort(() => { return Math.random() - 0.5});

Существуют и более качественные алгоритмы для перемешивания массивов. Например — алгоритм тасования Фишера-Йетса. Почитать о разных алгоритмах для перемешивания массивов можно здесь.

13. Создание глубоких копий объектов


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

const myClone = JSON.parse(JSON.stringify(originalObject));

Надо отметить, что если в originalObject есть циклические ссылки, то создать его копию не удастся. Эту технику рекомендуется использовать на простых объектах, которые вы создаёте сами.

Мелкую копию объекта можно создать с помощью синтаксиса spread:

const myClone = { ...orignalObject };

Итоги: о комбинировании и расширении кода однострочников


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

Уважаемые читатели! Какими примерами полезных JS-однострочников вы дополнили бы этот материал?



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


  1. yarkov
    20.06.2019 13:02

    Пункт 2

    const obj = {a:1};
    const myObjArray = [obj, obj];
    const deDupeObj = [...new Set(myObjArray)];
    const myArray = [{a:1}, {a:1}];
    const deDupe = [...new Set(myArray)];
    // Как и ожидалось
    console.log(deDupeObj); // [{a:1}]
    // Упс...
    console.log(deDupe); // [{a:1}, {a:1}]
    

    Эту ситуацию надо объяснить, раз уж взялись давать советы.


    1. Odrin
      20.06.2019 14:52
      +1

      Поведение ожидаемое и очевидное, что здесь объяснять?


      1. yarkov
        20.06.2019 15:29

        Для кого оно ожидаемое и очевидное, тот не почерпнет в статье для себя ничего нового. Ну а впрочем это только моё мнение…


        1. CoolCmd
          20.06.2019 19:29

          то, как передаются объекты (по ссылке) — это первые главы любого учебника по JS


          1. yarkov
            20.06.2019 19:46

            Я то в курсе. Ниже вот отписался.


            1. CoolCmd
              21.06.2019 00:28

              ссылки — это азы, их в учебниках объясняют, а не в статьях, которые рассчитаны на людей, уже во всю херачащих на JS.


              Для кого оно ожидаемое и очевидное, тот не почерпнет в статье для себя ничего нового.

              такие вещи, как обмен значений 2х переменных — вещь неочевидная даже для человека, который знает о destructuring assignment.


              1. faiwer
                21.06.2019 09:39

                +1, не приходило в голову, что destructuring assignment может работать и без декларации (const, var, let). Плюс я был почти уверен, что { ...myProperty && { propName: myProperty } } просто упадёт с ошибкой если myProperty будет non-object (не падает).


                1. Sirion
                  21.06.2019 09:50

                  Я это знал, но удивился, что деструктуризация работает и в следующем случае:

                  function swap(array, index1, index2){
                    [array[index1], array[index2]] = [array[index2], array[index1]];
                  }
                  


    1. NOCELL
      20.06.2019 18:45

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

      const obj = {a:1}
      здесь вы создали обьект.
      const deDupeObj = [...new Set(myObjArray)] 
      здесь вы сравниваете обьект с самим собой.

      const myArray = [{a:1}, {a:1}]
      здесь вы создаете два обьекта, и соотвественно с разными ссылками.
      const deDupe = [...new Set(myArray)]
      здесь вы сравниваете ссылки на два разных обьекта.


      1. yarkov
        20.06.2019 19:46
        +1

        Да мне то Вы зачем это объясняете? Я прекрасно это знаю. Коммент о том, что тот, кому будет полезна статья, может не знать этих нюансов.
        Сужу по вопросам на Тостере и в чатиках Телеграма. Частенько проскакивают попытки сделать массив уникальных объектов с помощью Set.


  1. Aingis
    20.06.2019 13:10
    +2

    1–12: Мама, я прочитал документацию Javascript! Смотри, как я могу!


    13: На самом деле такое копирование обладает рядом недостатков. JSON имеет в своём составе только примитивные структуры. В массивах undefined (и дырки) станут null. В объектах просто будут удалены. Типизированные массивы сконвертируются в обычные. Date станет строкой. Все функции, Map и Set и некоторые другие вообще потеряются, подобно undefined!


    Разумеется, потеряются и symbol-ссылки, и любые другие неперечисляемые свойства (которых не будет в for-in/Object.keys()), геттеры, сеттеры. Даже обычные объекты могут выдать что угодно, если у них (или в прототипе) есть метод .toJSON(). На циклических ссылках код вообще упадёт.


    1. JustDont
      20.06.2019 14:17

      13: На самом деле такое копирование обладает рядом недостатков.

      Эти вот «недостатки» — они не обязательно недостатки, иногда они наоборот крайне полезны. Единственное, что тут нужно иметь в виду, что прогон объектов через JSON — это всё-таки НЕ клонирование.

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


    1. 99designs
      21.06.2019 12:54

      Если понадобилось копировать сложный объект, скорее всего где то выше в архитектуре проблемы.


      1. JustDont
        21.06.2019 13:26

        Ну щас, ага.

        У вас есть стейт приложения. Пользователь в этот стейт вносит изменения, которые должны будут примениться по нажатии кнопки «применить изменения». Как будете хранить «грязный» стейт? Как дельту к чистому? И если никакие undo-redo заведомо не нужны — всё равно будете дельты хранить? И будете писать код по созданию дельт и их накатыванию, вместо того, чтоб отклонировать чистый стейт, а потом залить грязный поверх чистого (в одну строчку)?


        1. Sirion
          21.06.2019 13:42

          Immutable.js


          1. JustDont
            21.06.2019 13:49

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

            И к слову о этой ветке комментариев, Immutable.js — это как раз таки копирование объектов во все поля. Только зашитое в либу.


            1. Sirion
              21.06.2019 15:34

              А вот и нет. Там хитрые внутренние механизмы, избегающие дублирования данных и лишней работы.


              1. JustDont
                21.06.2019 15:48

                Там хитрые внутренние механизмы, избегающие дублирования данных и лишней работы.

                Никакая внутренняя хитрость не поможет вам сохранить два указателя на данные по той же цене, что и один указатель. Я в курсе, что immutable.js очень неплохо оптимизирован (и вообще либа концептуально хорошая), но то, что он делает — это всё равно копирование структур данных. Даже если копируется только левая сторона (указатели).


                1. ganqqwerty
                  21.06.2019 19:27

                  Дык это ж по четыре байта на указатель, мало же!


        1. faiwer
          21.06.2019 16:27

          Решал подобную задачу. Активно использовал иммутабельность (без immutable.js). В итоге для redo/undo не хранил никаких дельт, а хранил ссылку на предыдущий стейт целиком. Сами понимаете, вес одного undo-среза был крошечный.


          Вопрос с сериализацией и десериализацией решил просто: кастомный cloneObject метод, который используя Map упаковывал state в json, где все circular references были строкой вида $circular$firstPath. И был такой же метод десериализации который строил такой же объект восстанавливая все ссылки. На всё про всё строк 30 кода.


  1. Sirion
    20.06.2019 14:01

    1. 0xd34df00d
      20.06.2019 16:30

      Хорошо вам там. В плюсах аналогичный подход почти наверняка уронит sort и прочие алгоритмы, ожидающие корректный порядок.


      1. Sirion
        20.06.2019 22:00

        Вот прям уронит? Мне кажется, все быстрые алгоритмы сортировки должны такой компаратор нормально переварить, потому что у них тупо нет времени, чтобы наткнуться на неконсистентность. Потому что неконсистентность — это когда мы получили результат сравнения, противоречащий предыдущим результатам. Но если он противоречит им — значит, мы могли его знать ещё до того, как провели сравнение (предполагая, что компаратор «нормальный»).


        1. 0xd34df00d
          20.06.2019 22:33
          +1

          Можно вылезти за границы массива, например, или уйти в бесконечную рекурсию/цикл, или ещё чего натворить. Вот я сконструировал пример, который валит libstdc++, примерно с третьей попытки.


          Собственно, эта страница приоткрывает завесу: требуется, чтобы предикат описывал некоторый strict weak order со всей его аксиоматикой.


          На CppNow 2019 был доклад Гашпера про порядки и как они относятся к C++20'овому operator spaceship, и в лицах ряда людей читалось непонимание математической части (хотя там ничего принципиально сложного не было, хоть я и дико не согласен с философией его подхода). Но это так, навеянные мысли вслух к вопросу о том, зачем программистам математика.


  1. 1andy
    20.06.2019 17:48
    +2

    Вредный «однострочник»:

    myArray.sort(() => { return Math.random() - 0.5});


    Если хочется использовать Math.random(), то в одну строку примерно так
    arr = arr.map(a => ({sort: Math.random(), value: a})).sort((a, b) => a.sort - b.sort).map(a => a.value)


    Детали: stackoverflow.com/questions/962802/is-it-correct-to-use-javascript-array-sort-method-for-shuffling


  1. Tannenfels
    20.06.2019 19:23
    +1

    Давайте лучше полезные однострочники на Perl


    1. red_andr
      20.06.2019 19:57
      +1

      Или на Питоне. Мой любимый, квиксорт в одну строку:

      qs = lambda L: [] if L==[] else qs([x for x in L[1:] if x<L[0]]) + L[0:1] + qs([x for x in L[1:] if x>=L[0]])


      1. vp_arth
        20.06.2019 20:09

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


        1. red_andr
          20.06.2019 20:13

          Да, тут скорее для наглядности или искусства ради. У него есть проблема есть и посерьёзнее, будучи рекурсивным не будет работать для списков больше определённого размера. Причём не очень большого, порядка тысячи.


      1. the_o
        21.06.2019 12:54
        +1

        Аж даже любопытно стало вспомнить перл и написать то же самое на нём =)

        $qs = sub { my ($car, @cdr) = @_; @_ == () ? () : ($qs->(grep { $_ < $car} @cdr), $_[0], $qs->(grep { $_ >= $car} @cdr)) };


        1. vp_arth
          21.06.2019 13:45
          +1

          Ну и грех было бы не перевести на javascript, раз уж это тема статьи:

          const qs = a=>a.length?[...qs(a.slice(1).filter(e=>e<a[0])),a[0],...qs(a.slice(1).filter(e=>e>=a[0]))]:[];
          



  1. missingdays
    20.06.2019 20:59
    +3

    что здесь используется мелкое копирование свойств объектов

    translate.google.com/#view=home&op=translate&sl=en&tl=ru&text=shallow%20copying
    Почему-то знал, что скажет google переводчик еще до того, как ввел в него эту фразу.


  1. ArVaganov
    21.06.2019 03:05

    JSON.parse(JSON.stringify(originalObject));
    
    Удачи в копировании объектов с properties NaN, Infinity, Function, и многими другими.


  1. ganqqwerty
    21.06.2019 12:24

    Если честно, не люблю эти однострочники, некоторые из них просто щекочат эго джунов, не принося никакой пользы. Да, их надо знать, чтобы распознавать в чужом коде, но свой код должен быть кристально ясен.
    Если вы удаляете дубликаты из массива, как насчет функции `removeDuplicates(arr, predicate)`? Вы можете реализовать ее оптимальным способом, она будет фурычить быстрее, а постороннему программисту будет сразу ясно — вот тут удаляют дубликаты. Ну или в каком-нибудь lodash такая функция наверняка есть. Вы можете гарантировать, что ваш код всегда будут читать любители и знатоки однострочников? Или может быть, в вашем проекте появляются иногда джуны, или переученные за две недели с джавы «фуллстэк-девелоперы»? Сколько времени это будет стоить вашей компании на промежутке в хотя бы год? Если ваша зарплата включает в себя процент от прибылей, такие вопросы — не праздные.

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


  1. ganqqwerty
    21.06.2019 12:24

    Или вот пункт 8 — ну спотыкается взгляд о такие конструкции. А что если в объекте справа переименовалось свойство, а у вас нет тайпскрипта и приличной IDE, которая бы все подчеркнуло?


  1. ganqqwerty
    21.06.2019 12:31

    Пункт 13 — очень плохо давать такие советы. Во-первых, автор просто так ляпнул, что этот способ медленный. Он не медленный, он самый быстрый.
    Во-вторых, применять этот способ нужно не когда у вас мало времени, а когда вы точно уверены, что объекты будут простенькие, без циклических ссылок или ссылок на какие-нибудь гигантские другие объекты и нужно чтобы это было супер-быстро, потому что делается миллиарды раз. Да я могу маленький движок графовой БД таким, что попытка `stringify` одного из узлов выведет полностью всю эту базу. Первый вопрос, который надо задавать человеку, делающем deepCopy — «а без deepCopy точно ничего не получится»?


    1. WanSpi
      21.06.2019 14:37

      Он не медленный, он самый быстрый.

      В каком месте он самый быстрый? Я прошелся по тесту в Вашей ссылке, и мне показоло что он самый медленный, при этом в два раза медленее того же 'Object.assign({}, obj);'


      1. ganqqwerty
        21.06.2019 14:41
        +1

        дык а Object.assign делает shallow copy, не deep copy


        1. WanSpi
          21.06.2019 19:56

          Согласен, но собственно способ 'JSON.parse(JSON.stringify(obj))' копирует очень малую часть от самого объекта, так что я бы не стал их сравнивать, так как одно и другое далеко от полного копирования объекта.


      1. ganqqwerty
        21.06.2019 14:56

        Хахаха, а вот тут уже я, не подумав, ляпнул. И впрямь, самый медленный, на jsbench 100% — это максимум, чем меньше процентов тем лучше. Как удалять комменты на хабре


  1. ganqqwerty
    21.06.2019 12:37

    Пункт 12 — так выглядит код говнокодера и script-kiddy, не понимающего ни что такое инкапсуляция, ни что такое предусловия. Ты взял неизвестный тебе алгоритм сортировки, который ожидает консистентную функцию сравнения (если A>B, то B<A, а если A>B и B>C, то A>C) и передал туда фигню вместо консистентной функции сравнения. Как будет работать неизвестный тебе алгоритм, если передать в него не то, что он ожидает? Завершится ли он когда-нибудь? Если завершится, то за какое время? Ах, «но ведь оно работает, я пробовал во всех браузерах?»

    P.S. это не обращение к авторам статьи, это просто моя клокочущая ненависть к таким идеям.


  1. rvs2016
    21.06.2019 12:54

    > Приведение значений к логическому типу
    > myBoolean = !!myVariable;

    А зачем?
    Ведь, если myVariable = 1, то

    if ( myVariable ) {
        // я и без boolean, а на честном <s>слове</s> integer попаду в эту ветвь оператора if
    }


    1. WanSpi
      21.06.2019 13:16

      Вот тоже не знаю зачем это делать, разве что при проверке ===, хотя тоже не понятно зачем это делать, помню даже когда то спорил с одним 'специалистом', который с пеной у рта доказывал что нужно писать именно 'if (!!myVariable)', хотя так и не смог привести доказательства, когда данный пример будет отличаться от 'if (myVariable)'


      1. JustDont
        21.06.2019 13:31

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


        1. WanSpi
          21.06.2019 13:42

          Полностью с Вами согласен, я лишь приводил пример только про ифы.


      1. the_o
        21.06.2019 16:14
        +1

        Чаще всего подобное приведение к boolean встречается в конструкциях типа switch(true), т.к. switch как раз сравнивает строго:

        const myVariable = 1;
        switch (true) {
            case myVariable:
               console.log('Эта ветка не отработает');
               break;
            
            case !!myVariable:
                console.log('А эта отрабтает');
                break;
        }


        1. WanSpi
          21.06.2019 16:38
          +2

          Как я уже писал выше, это было сказано лишь для ифа, а для строгого сравнения — да, можно такое пременить.

          Но чисто для интереса хотело бы спросить, где вообще такой свитч можно применить? Не лучше для данного примера использовать обычный if/else?


          1. faiwer
            21.06.2019 19:31

            Такой switch можно использовать если очень хочется не пройти code-review :)


          1. the_o
            21.06.2019 19:35

            Для данного конкретного, естественно, if'а достаточно. Даже просто && обойтись можно. Это была просто демонстрация того, что switch требует строгого равенства, и если об этом забыть, можно получить неожиданный результат.

            А сам switch(true) именно с необходимостью приводить к boolean я нередко наблюдал в ситуациях, подобных вот этой:

            getSomeMeasurementAsync((err, data) => {
                switch (true) {
                    case !!err:
                        handleError(`Error getting measurement`, err);
                        break;
            
                    case !!data.error:
                        handleError(`Measurement error`, data.error);
                        break;
            
                    default:
                        handleMeasurement(data.measurement);
                }
            });


            1. WanSpi
              21.06.2019 19:45
              +1

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


      1. faiwer
        21.06.2019 19:29

        !!variable очень распространённый "хак". Используется когда вам нужно гарантировано привести к boolean-у и не хочется писать variable ? true : false. Т.е. не в if(), until(), repeat() и пр., а скорее при формировании нового объекта где по контракту должен быть boolean.


        1. WanSpi
          21.06.2019 19:37

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


          1. faiwer
            21.06.2019 19:46

            Есть даже линтеры чтобы if(!!...) не использовали :-)


            1. WanSpi
              21.06.2019 19:51

              Вообще я не понимаю от куда пошла мода писать if(!!...), так как где то два года назад, много кто мне об этом начал говорить, хотя выводов так и не предоставляли, лишь в стиле «так надо», как будто кто то, что то ляпнул, и все как стадо начали повторять…


      1. ganqqwerty
        22.06.2019 03:04

        Ну а если у вас какой-нить filter, и вы не знаете, что у него внутри — строгое или нестрогое сравнение?


    1. vvadzim
      24.06.2019 13:22

      Ну boolean часто нужен всё-таки. Выше про сериализацию писали. Иногда надо сохранить логическое значение надолго, а прилетает всё что угодно. Приведение к boolean перед сохранением позволяет отпустить значение для GC.

      Но я сам очень не люблю

      !!value
      и тупо пишу
      Boolean(value)


  1. YemSalat
    21.06.2019 14:33
    +2

    const myObject = { ...myProperty && { propName: myProperty } }

    Да ну, такое надо на ревью обратно отправлять.


    1. vvadzim
      24.06.2019 13:25

      Ну вот, а я так пишу :(
      А как было бы лучше? if'ами?


  1. genew
    21.06.2019 17:20
    +1

    Пункт 10. Быстрое создание числовых массивов
    На MDN есть еще вот такой пример:

    // Генерирования последовательности чисел
    Array.from({ length: 5 }, (v, k) => k); 
    // [0, 1, 2, 3, 4]