Какие способы создания массивов ты знаешь?

👨‍💻 Frontend Developer 🟠 Может встретиться 🎚️ Легкий
#JavaScript #массивы #База JS

Краткий ответ

Создание массивов в JavaScript можно выполнить несколькими способами: литерал массива [] (рекомендуется), конструктор new Array(), Array.of(), Array.from(), методы split(), map(), filter() и другие. Самый популярный и рекомендуемый способ — использование литерала массива.

Основные способы:

  • [] — литерал массива (рекомендуется)
  • new Array() — конструктор массива
  • Array.of() — создание из элементов
  • Array.from() — создание из итерируемых объектов

Что означает создание массива

Создание массива — это процесс инициализации новой структуры данных, которая может хранить упорядоченную коллекцию элементов. В JavaScript массивы являются объектами с числовыми индексами и специальными методами.

Зачем нужны разные способы

// Разные задачи требуют разных подходов
const empty = []; // Пустой массив
const withData = [1, 2, 3]; // С данными
const fromString = "hello".split(""); // Из строки
const range = Array.from({length: 5}, (_, i) => i); // Диапазон
 
console.log(empty); // []
console.log(withData); // [1, 2, 3]
console.log(fromString); // ['h', 'e', 'l', 'l', 'o']
console.log(range); // [0, 1, 2, 3, 4]

Способы создания массивов

1. Литерал массива [] (рекомендуется)

// Пустой массив
const empty = [];
 
// С элементами
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "hello", true, null, {name: "John"}];
 
// Многомерные массивы
const matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];
 
// С вычисляемыми значениями
const calculated = [2 + 2, Math.PI, new Date()];
 
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(mixed); // [1, "hello", true, null, {name: "John"}]

Преимущества:

  • ✅ Самый читаемый и понятный синтаксис
  • ✅ Быстрый и эффективный
  • ✅ Поддерживается всеми браузерами
  • ✅ Рекомендуется стандартами кодирования

Недостатки:

  • ❌ Нельзя создать массив определённой длины без элементов

2. Конструктор new Array()

// Пустой массив
const empty = new Array();
 
// Массив определённой длины
const withLength = new Array(5); // [empty × 5]
 
// С элементами
const withElements = new Array(1, 2, 3, 4, 5);
 
// Осторожно с одним числовым аргументом!
const surprise = new Array(3); // [empty × 3], не [3]!
const expected = new Array("3"); // ["3"]
 
console.log(withLength); // [undefined, undefined, undefined, undefined, undefined]
console.log(withElements); // [1, 2, 3, 4, 5]
console.log(surprise.length); // 3
console.log(expected); // ["3"]

Преимущества:

  • ✅ Можно создать массив определённой длины
  • ✅ Поддерживается всеми браузерами
  • ✅ Явно показывает намерение создать массив

Недостатки:

  • ❌ Неожиданное поведение с одним числовым аргументом
  • ❌ Более длинный синтаксис
  • ❌ Создаёт “дырявые” массивы

3. Array.of() (ES6)

// Создание массива из аргументов
const numbers = Array.of(1, 2, 3, 4, 5);
const single = Array.of(3); // [3], не массив длины 3!
const mixed = Array.of("hello", 42, true, null);
 
// Сравнение с new Array()
console.log(new Array(3)); // [empty × 3]
console.log(Array.of(3)); // [3]
 
// Полезно для создания массивов из переменных
function createArray(...args) {
  return Array.of(...args);
}
 
console.log(createArray(1, 2, 3)); // [1, 2, 3]

Преимущества:

  • ✅ Предсказуемое поведение
  • ✅ Решает проблему new Array() с одним аргументом
  • ✅ Хорошо работает с spread оператором

Недостатки:

  • ❌ Не поддерживается в IE
  • ❌ Менее популярен чем литерал

4. Array.from() (ES6)

// Из строки
const fromString = Array.from("hello");
console.log(fromString); // ['h', 'e', 'l', 'l', 'o']
 
// Из Set
const fromSet = Array.from(new Set([1, 2, 2, 3, 3]));
console.log(fromSet); // [1, 2, 3]
 
// Из NodeList
const elements = document.querySelectorAll('div');
const elementsArray = Array.from(elements);
 
// С функцией преобразования
const doubled = Array.from([1, 2, 3], x => x * 2);
console.log(doubled); // [2, 4, 6]
 
// Создание диапазона
const range = Array.from({length: 5}, (_, i) => i + 1);
console.log(range); // [1, 2, 3, 4, 5]
 
// Создание массива с повторяющимися значениями
const repeated = Array.from({length: 3}, () => "hello");
console.log(repeated); // ["hello", "hello", "hello"]

Преимущества:

  • ✅ Универсальный метод конвертации
  • ✅ Поддерживает функцию преобразования
  • ✅ Работает с любыми итерируемыми объектами
  • ✅ Отлично для создания диапазонов

Недостатки:

  • ❌ Не поддерживается в IE
  • ❌ Может быть избыточным для простых случаев

5. Методы строк

// split() - разделение строки
const words = "hello world javascript".split(" ");
console.log(words); // ["hello", "world", "javascript"]
 
const chars = "abc".split("");
console.log(chars); // ["a", "b", "c"]
 
// match() - поиск совпадений
const numbers = "123-456-789".match(/\d+/g);
console.log(numbers); // ["123", "456", "789"]
 
// Деструктуризация строки
const [...letters] = "hello";
console.log(letters); // ['h', 'e', 'l', 'l', 'o']

6. Методы массивов

// map() - преобразование
const original = [1, 2, 3];
const doubled = original.map(x => x * 2);
console.log(doubled); // [2, 4, 6]
 
// filter() - фильтрация
const numbers = [1, 2, 3, 4, 5, 6];
const even = numbers.filter(x => x % 2 === 0);
console.log(even); // [2, 4, 6]
 
// slice() - копирование части
const source = [1, 2, 3, 4, 5];
const copy = source.slice(); // Полная копия
const part = source.slice(1, 4); // [2, 3, 4]
 
// concat() - объединение
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4]

7. Spread оператор (…)

// Копирование массива
const original = [1, 2, 3];
const copy = [...original];
console.log(copy); // [1, 2, 3]
 
// Объединение массивов
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4]
 
// Добавление элементов
const base = [2, 3];
const extended = [1, ...base, 4, 5];
console.log(extended); // [1, 2, 3, 4, 5]
 
// Из итерируемых объектов
const fromSet = [...new Set([1, 2, 2, 3])];
console.log(fromSet); // [1, 2, 3]
 
const fromString = [..."hello"];
console.log(fromString); // ['h', 'e', 'l', 'l', 'o']

Сравнение производительности

Тест производительности

function performanceTest() {
  const iterations = 1000000;
  
  // Тест 1: Литерал массива
  console.time('Literal []');
  for (let i = 0; i < iterations; i++) {
    const arr = [1, 2, 3, 4, 5];
  }
  console.timeEnd('Literal []');
  
  // Тест 2: new Array()
  console.time('new Array()');
  for (let i = 0; i < iterations; i++) {
    const arr = new Array(1, 2, 3, 4, 5);
  }
  console.timeEnd('new Array()');
  
  // Тест 3: Array.of()
  console.time('Array.of()');
  for (let i = 0; i < iterations; i++) {
    const arr = Array.of(1, 2, 3, 4, 5);
  }
  console.timeEnd('Array.of()');
  
  // Тест 4: Array.from()
  console.time('Array.from()');
  for (let i = 0; i < iterations; i++) {
    const arr = Array.from([1, 2, 3, 4, 5]);
  }
  console.timeEnd('Array.from()');
}
 
performanceTest();

Результаты (приблизительные)

МетодВремя (мс)ЧитаемостьПоддержка
[]~50ОтличнаяВсе браузеры
new Array()~80ХорошаяВсе браузеры
Array.of()~120ХорошаяES6+
Array.from()~200ОтличнаяES6+

Практические примеры

1. Создание диапазонов чисел

class RangeGenerator {
  // Простой диапазон
  static range(start, end) {
    return Array.from(
      {length: end - start + 1}, 
      (_, i) => start + i
    );
  }
  
  // Диапазон с шагом
  static rangeWithStep(start, end, step = 1) {
    const length = Math.floor((end - start) / step) + 1;
    return Array.from(
      {length}, 
      (_, i) => start + i * step
    );
  }
  
  // Диапазон с функцией
  static rangeWithFunction(length, fn) {
    return Array.from({length}, (_, i) => fn(i));
  }
}
 
// Использование
console.log(RangeGenerator.range(1, 5)); // [1, 2, 3, 4, 5]
console.log(RangeGenerator.rangeWithStep(0, 10, 2)); // [0, 2, 4, 6, 8, 10]
console.log(RangeGenerator.rangeWithFunction(5, i => i * i)); // [0, 1, 4, 9, 16]

2. Создание матриц

class MatrixCreator {
  // Создание пустой матрицы
  static createEmpty(rows, cols, defaultValue = 0) {
    return Array.from(
      {length: rows}, 
      () => Array.from({length: cols}, () => defaultValue)
    );
  }
  
  // Единичная матрица
  static createIdentity(size) {
    return Array.from(
      {length: size}, 
      (_, i) => Array.from(
        {length: size}, 
        (_, j) => i === j ? 1 : 0
      )
    );
  }
  
  // Матрица с функцией
  static createWithFunction(rows, cols, fn) {
    return Array.from(
      {length: rows}, 
      (_, i) => Array.from(
        {length: cols}, 
        (_, j) => fn(i, j)
      )
    );
  }
}
 
// Использование
const empty = MatrixCreator.createEmpty(3, 3);
console.log(empty);
// [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
 
const identity = MatrixCreator.createIdentity(3);
console.log(identity);
// [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
 
const multiplication = MatrixCreator.createWithFunction(3, 3, (i, j) => i * j);
console.log(multiplication);
// [[0, 0, 0], [0, 1, 2], [0, 2, 4]]

3. Парсинг и обработка данных

class DataParser {
  // Парсинг CSV
  static parseCSV(csvString) {
    return csvString
      .trim()
      .split('\n')
      .map(row => row.split(',').map(cell => cell.trim()));
  }
  
  // Создание массива из объекта
  static objectToArray(obj, keyName = 'key', valueName = 'value') {
    return Object.entries(obj).map(([key, value]) => ({
      [keyName]: key,
      [valueName]: value
    }));
  }
  
  // Группировка массива
  static groupBy(array, keyFn) {
    const groups = {};
    array.forEach(item => {
      const key = keyFn(item);
      if (!groups[key]) {
        groups[key] = [];
      }
      groups[key].push(item);
    });
    return groups;
  }
}
 
// Использование
const csv = `name,age,city
John,25,New York
Jane,30,London
Bob,35,Paris`;
 
const parsed = DataParser.parseCSV(csv);
console.log(parsed);
// [['name', 'age', 'city'], ['John', '25', 'New York'], ...]
 
const obj = {a: 1, b: 2, c: 3};
const arrayFromObj = DataParser.objectToArray(obj);
console.log(arrayFromObj);
// [{key: 'a', value: 1}, {key: 'b', value: 2}, {key: 'c', value: 3}]

Задачи для практики

Задача 1

// Создайте массив чисел от 1 до 10 тремя разными способами
const method1 = ?;
const method2 = ?;
const method3 = ?;
 
console.log(method1); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Ответ
const method1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const method2 = Array.from({length: 10}, (_, i) => i + 1);
const method3 = [...Array(10)].map((_, i) => i + 1);

Задача 2

// Что выведет этот код?
const a = new Array(3);
const b = Array.of(3);
const c = [3];
 
console.log(a.length);
console.log(b.length);
console.log(c.length);
console.log(a[0]);
console.log(b[0]);
console.log(c[0]);
Ответ

3, 1, 1, undefined, 3, 3 — new Array(3) создаёт массив длины 3 с пустыми слотами, Array.of(3) и [3] создают массив с одним элементом 3.


Задача 3

// Создайте функцию, которая создаёт массив
// повторяющихся значений
function repeat(value, times) {
  // Ваш код
}
 
console.log(repeat("hello", 3)); // ["hello", "hello", "hello"]
console.log(repeat(42, 5)); // [42, 42, 42, 42, 42]
Ответ
function repeat(value, times) {
  return Array.from({length: times}, () => value);
  // или
  // return new Array(times).fill(value);
  // или
  // return [...Array(times)].map(() => value);
}

Современные возможности

1. Использование с TypeScript

// Типизированные массивы
function createNumberArray(length: number): number[] {
  return Array.from({length}, (_, i) => i + 1);
}
 
function createTypedArray<T>(length: number, factory: (index: number) => T): T[] {
  return Array.from({length}, (_, i) => factory(i));
}
 
// Использование
const numbers = createNumberArray(5); // number[]
const strings = createTypedArray(3, i => `item-${i}`); // string[]

2. Создание с async/await

class AsyncArrayCreator {
  // Создание массива с асинхронными данными
  static async createFromPromises(promises) {
    return Promise.all(promises);
  }
  
  // Создание с асинхронной функцией
  static async createWithAsyncFunction(length, asyncFn) {
    const promises = Array.from({length}, (_, i) => asyncFn(i));
    return Promise.all(promises);
  }
  
  // Последовательное создание
  static async createSequentially(length, asyncFn) {
    const result = [];
    for (let i = 0; i < length; i++) {
      result.push(await asyncFn(i));
    }
    return result;
  }
}
 
// Использование
const urls = ['url1', 'url2', 'url3'];
const promises = urls.map(url => fetch(url));
const responses = await AsyncArrayCreator.createFromPromises(promises);
 
const data = await AsyncArrayCreator.createWithAsyncFunction(5, async (i) => {
  const response = await fetch(`/api/data/${i}`);
  return response.json();
});

3. Создание с генераторами

function* numberGenerator(start, end) {
  for (let i = start; i <= end; i++) {
    yield i;
  }
}
 
function* fibonacciGenerator(count) {
  let a = 0, b = 1;
  for (let i = 0; i < count; i++) {
    yield a;
    [a, b] = [b, a + b];
  }
}
 
// Создание массивов из генераторов
const numbers = [...numberGenerator(1, 10)];
console.log(numbers); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 
const fibonacci = Array.from(fibonacciGenerator(10));
console.log(fibonacci); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Лучшие практики

✅ Рекомендации

// 1. Используйте литерал массива для простых случаев
const numbers = [1, 2, 3, 4, 5]; // ✅ Лучший выбор
 
// 2. Array.from() для преобразований и диапазонов
const range = Array.from({length: 10}, (_, i) => i + 1); // ✅ Отлично
 
// 3. Spread для копирования и объединения
const copy = [...original]; // ✅ Современно и читаемо
const combined = [...arr1, ...arr2]; // ✅ Ясно и эффективно
 
// 4. Используйте типизацию в TypeScript
function createArray<T>(items: T[]): T[] {
  return [...items]; // ✅ Типобезопасно
}
 
// 5. Документируйте сложные случаи
/**
 * Создаёт двумерный массив (матрицу)
 * @param {number} rows - Количество строк
 * @param {number} cols - Количество столбцов
 * @param {*} defaultValue - Значение по умолчанию
 */
function createMatrix(rows, cols, defaultValue = 0) {
  return Array.from(
    {length: rows}, 
    () => Array.from({length: cols}, () => defaultValue)
  );
}

❌ Чего избегать

// ❌ Не используйте new Array() с одним числовым аргументом
const bad = new Array(5); // Создаёт [empty × 5]
const good = Array.from({length: 5}, () => undefined); // ✅ Явно
 
// ❌ Не полагайтесь на автоматическое преобразование
const bad = Array("5"); // Может быть неожиданным
const good = ["5"]; // ✅ Ясно и понятно
 
// ❌ Не создавайте массивы в циклах без необходимости
for (let i = 0; i < 1000; i++) {
  const arr = []; // ❌ Неэффективно
  // ... работа с arr
}
 
// ✅ Создайте один раз, переиспользуйте
const arr = [];
for (let i = 0; i < 1000; i++) {
  arr.length = 0; // Очистка
  // ... работа с arr
}
 
// ❌ Не забывайте про производительность
const bad = Array.from(Array.from(Array.from([1,2,3]))); // Избыточно
const good = [1, 2, 3]; // ✅ Просто и быстро

Частые ошибки

1. Путаница с new Array()

// ❌ Проблема
function createArray(size) {
  return new Array(size); // Создаёт пустые слоты!
}
 
const arr = createArray(3);
console.log(arr); // [empty × 3]
console.log(arr.map(x => 1)); // [empty × 3] - map пропускает пустые слоты!
 
// ✅ Решение
function createArray(size, defaultValue = undefined) {
  return Array.from({length: size}, () => defaultValue);
}
 
const arr = createArray(3, 0);
console.log(arr); // [0, 0, 0]
console.log(arr.map(x => x + 1)); // [1, 1, 1]

2. Неправильное копирование массивов

// ❌ Проблема
const original = [[1, 2], [3, 4]];
const copy = [...original]; // Поверхностная копия!
 
copy[0][0] = 999;
console.log(original[0][0]); // 999 - оригинал изменился!
 
// ✅ Решение для глубокого копирования
function deepCopyArray(arr) {
  return arr.map(item => 
    Array.isArray(item) ? deepCopyArray(item) : item
  );
}
 
const original = [[1, 2], [3, 4]];
const copy = deepCopyArray(original);
copy[0][0] = 999;
console.log(original[0][0]); // 1 - оригинал не изменился

3. Проблемы с производительностью

// ❌ Проблема - создание больших массивов неэффективно
function createLargeArray() {
  const arr = [];
  for (let i = 0; i < 1000000; i++) {
    arr.push(i); // Много операций push
  }
  return arr;
}
 
// ✅ Решение - предварительное выделение памяти
function createLargeArray() {
  return Array.from({length: 1000000}, (_, i) => i);
}
 
// ✅ Или использование типизированных массивов для чисел
function createLargeNumberArray() {
  const arr = new Int32Array(1000000);
  for (let i = 0; i < arr.length; i++) {
    arr[i] = i;
  }
  return arr;
}

Резюме

Создание массивов — это фундаментальная операция в JavaScript с множеством подходов:

Основные способы:

  • [] — самый быстрый и читаемый
  • new Array() — для массивов определённой длины
  • Array.of() — предсказуемое создание из элементов
  • Array.from() — универсальный для преобразований

Выбор способа зависит от:

  • 🚀 Производительности — литерал [] самый быстрый
  • 📖 Читаемости — литерал и Array.from() самые понятные
  • 🌐 Поддержки браузеров — литерал и new Array() везде
  • 🎯 Задачи — разные способы для разных целей

Рекомендации:

// Для большинства случаев
const arr = [1, 2, 3];
 
// Для диапазонов и преобразований
const range = Array.from({length: 10}, (_, i) => i + 1);
 
// Для копирования и объединения
const copy = [...original];
const combined = [...arr1, ...arr2];
 
// Для создания из итерируемых объектов
const fromSet = [...new Set([1, 2, 2, 3])];

Понимание различий между способами — это основа эффективной работы с массивами в JavaScript!


Хотите больше статей для подготовки к собеседованиям? Подписывайтесь на EasyAdvice(@AleksandrEmolov_EasyAdvice), добавляйте сайт в закладки и совершенствуйтесь каждый день 💪