← Назад к вопросам

Как работает метод map?

1.6 Junior🔥 241 комментариев
#JavaScript Core

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

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как работает метод map?

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

Синтаксис

const newArray = array.map((element, index, array) => {
  // преобразование элемента
  return transformedElement;
});

Параметры функции обратного вызова

  1. element — текущий элемент массива
  2. index — индекс текущего элемента (опционально)
  3. array — исходный массив (опционально)
const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map((num, index, arr) => {
  console.log(`Индекс: ${index}, Элемент: ${num}, Массив:`, arr);
  return num * 2;
});

console.log(doubled); // [2, 4, 6, 8, 10]

Основное назначение и примеры

1. Простое преобразование

const prices = [100, 200, 300];
const withTax = prices.map(price => price * 1.13); // Налог 13%

console.log(withTax); // [113, 226, 339]

2. Преобразование объектов

const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 28 }
];

// Извлечение только имён
const names = users.map(user => user.name);
console.log(names); // ['Alice', 'Bob', 'Charlie']

// Создание новых объектов
const usersWithId = users.map((user, index) => ({
  ...user,
  id: index + 1
}));

console.log(usersWithId);
// [
//   { name: 'Alice', age: 25, id: 1 },
//   { name: 'Bob', age: 30, id: 2 },
//   { name: 'Charlie', age: 28, id: 3 }
// ]

3. Преобразование строк

const words = ['hello', 'world', 'javascript'];
const capitalized = words.map(word => 
  word.charAt(0).toUpperCase() + word.slice(1)
);

console.log(capitalized); // ['Hello', 'World', 'Javascript']

4. Конвертация типов

const stringNumbers = ['1', '2', '3', '4', '5'];
const numbers = stringNumbers.map(Number);

console.log(numbers); // [1, 2, 3, 4, 5]

// То же самое с явной функцией
const numbers2 = stringNumbers.map(str => parseInt(str));
console.log(numbers2); // [1, 2, 3, 4, 5]

Как map работает под капотом

// Упрощённая реализация map:
Array.prototype.myMap = function(callback, thisArg) {
  const result = [];
  
  for (let i = 0; i < this.length; i++) {
    // Проверка, что элемент существует
    if (i in this) {
      // Вызов callback для каждого элемента
      result[i] = callback.call(thisArg, this[i], i, this);
    }
  }
  
  return result;
};

const arr = [1, 2, 3];
const result = arr.myMap(x => x * 2);
console.log(result); // [2, 4, 6]

Важное свойство: map создаёт новый массив

const original = [1, 2, 3];
const mapped = original.map(x => x * 2);

console.log(original === mapped); // false — разные массивы!
console.log(original); // [1, 2, 3] — не изменился
console.log(mapped);   // [2, 4, 6] — новый массив

Это контрастирует с методами, которые изменяют исходный массив, такими как forEach, splice, reverse.

Параметр thisArg

Второй параметр map позволяет указать, что будет this внутри функции обратного вызова:

const multiplier = {
  factor: 2
};

const numbers = [1, 2, 3, 4];
const result = numbers.map(function(num) {
  return num * this.factor;
}, multiplier); // multiplier становится this

console.log(result); // [2, 4, 6, 8]

// С стрелочными функциями this не работает
const result2 = numbers.map(num => {
  // this здесь не из multiplier, а из внешнего контекста
  return num * 2;
}, multiplier); // multiplier игнорируется

Сравнение с другими методами

map vs forEach

const arr = [1, 2, 3];

// map — возвращает новый массив
const mapped = arr.map(x => x * 2);
console.log(mapped); // [2, 4, 6]

// forEach — ничего не возвращает, для побочных эффектов
arr.forEach(x => console.log(x * 2));
// 2
// 4
// 6
console.log(arr.forEach(x => x * 2)); // undefined

map vs filter

const numbers = [1, 2, 3, 4, 5];

// map — преобразует
const doubled = numbers.map(x => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// filter — отбирает элементы
const evens = numbers.filter(x => x % 2 === 0);
console.log(evens); // [2, 4]

map vs reduce

const numbers = [1, 2, 3, 4, 5];

// map — один элемент входа → один элемент выхода
const doubled = numbers.map(x => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// reduce — накапливает результат
const sum = numbers.reduce((acc, x) => acc + x, 0);
console.log(sum); // 15

Цепочки преобразований (chaining)

const data = [1, 2, 3, 4, 5];

const result = data
  .map(x => x * 2)           // [2, 4, 6, 8, 10]
  .filter(x => x > 5)         // [6, 8, 10]
  .map(x => ({ value: x }))   // [{ value: 6 }, { value: 8 }, { value: 10 }]
  .map(obj => obj.value * 2); // [12, 16, 20]

console.log(result); // [12, 16, 20]

Важные особенности

1. map пропускает пустые слоты (sparse arrays)

const arr = [1, , 3]; // Пустой слот на индексе 1
console.log(arr.length); // 3

const mapped = arr.map(x => x * 2);
console.log(mapped); // [2, <пустой слот>, 6]
console.log(mapped.length); // 3

2. map не изменяет исходный массив

const original = [{ id: 1 }, { id: 2 }];
const mapped = original.map(obj => ({
  ...obj,
  name: 'User' + obj.id
}));

console.log(original[0]); // { id: 1 } — не изменился
console.log(mapped[0]);   // { id: 1, name: 'User1' } — новый объект

3. map срабатывает для каждого элемента

let callCount = 0;
const arr = [1, 2, 3];

arr.map(x => {
  callCount++;
  return x * 2;
});

console.log(callCount); // 3 — callback вызван 3 раза

В React: рендеринг списков

// Очень частое использование в React
function UserList({ users }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>
          {user.name} (возраст: {user.age})
        </li>
      ))}
    </ul>
  );
}

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

// Не эффективно — лишний промежуточный массив
const result = arr
  .map(x => x * 2)   // Создаёт новый массив
  .filter(x => x > 5); // Создаёт ещё один новый массив

// Более эффективно
const result = arr
  .filter(x => x * 2 > 5) // Один проход
  .map(x => x * 2);

// Или с reduce для одного прохода
const result = arr.reduce((acc, x) => {
  if (x * 2 > 5) acc.push(x * 2);
  return acc;
}, []);

Заключение

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

  • Создаёт новый массив (не изменяет исходный)
  • Вызывает callback для каждого элемента
  • Возвращает массив той же длины
  • Идеален для преобразований и трансформаций данных
  • Основополагающий метод функционального программирования в JavaScript