JS6
Методы shift и unshift

Методы shift() и unshift()

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

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

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

Что делают shift и unshift

shift()

Метод shift() удаляет первый элемент массива и возвращает его значение. После удаления все остальные элементы сдвигаются на одну позицию влево, то есть элемент, который был под индексом 1, становится новым первым элементом с индексом 0.

Пример:

const fruits = ['яблоко', 'банан', 'апельсин'];
const first = fruits.shift();

console.log(first);  // 'яблоко'
console.log(fruits);  // ['банан', 'апельсин']

Если массив пустой, shift() просто вернёт undefined и не вызовет ошибки. Это удобно при обработке очередей, где заранее неизвестно, есть ли ещё элементы.

unshift()

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

Пример:

const fruits = ['банан', 'апельсин'];
const length = fruits.unshift('яблоко');

console.log(length);  // 3
console.log(fruits);  // ['яблоко', 'банан', 'апельсин']

В отличие от shift(), метод unshift() может добавить несколько значений сразу:

const list = [3, 4, 5];
list.unshift(1, 2);

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

Краткое сравнение методов

Метод Действие Что возвращает Изменяет массив
shift() Удаляет первый элемент Удалённый элемент Да
unshift() Добавляет элементы в начало Новую длину массива Да

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

Как изменяется массив после операций

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

Сдвиг индексов

Если массив выглядел так:

['a', 'b', 'c', 'd']

то после shift() он станет:

['b', 'c', 'd']

Индексы изменятся следующим образом:

  • 'b' переместится с индекса 1 на 0;
  • 'c' — с 2 на 1;
  • 'd' — с 3 на 2.

При unshift('x') в массиве:

['a', 'b', 'c']

получится:

['x', 'a', 'b', 'c']

Индексы всех старых элементов увеличатся на единицу.

Влияние на длину массива

Оба метода изменяют свойство length. После shift() длина уменьшается на 1, после unshift() — увеличивается на количество добавленных элементов.

Если обозначить исходную длину массива как L, то:

  • после shift() новая длина: L - 1;
  • после unshift(a, b, c) новая длина: L + 3.

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

Где shift и unshift особенно полезны

Очереди

Классический сценарий — реализация очереди. Очередь работает по принципу FIFO: первым пришёл — первым вышел. В такой модели shift() используется для извлечения элемента из начала, а push() — для добавления в конец. Хотя задача статьи посвящена shift и unshift, полезно понимать, что именно они часто участвуют в построении очередей и обратных очередей.

Где shift и unshift особенно полезны — Методы shift и unshift
Где shift и unshift особенно полезны — Методы shift и unshift

Пример очереди:

const queue = ['задача 1', 'задача 2', 'задача 3'];

const current = queue.shift();
console.log(current); // 'задача 1'
console.log(queue);   // ['задача 2', 'задача 3']

Стекоподобные или приоритетные сценарии

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

Работа с последовательностями

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

Примеры использования в реальном коде

Последовательная обработка элементов

const tasks = ['проверить почту', 'созвониться', 'отправить отчёт'];

while (tasks.length > 0) {
  const task = tasks.shift();
  console.log('Выполняется:', task);
}

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

Добавление важных элементов в начало

const timeline = ['событие 2', 'событие 3'];
timeline.unshift('событие 1');

console.log(timeline); // ['событие 1', 'событие 2', 'событие 3']

Этот приём помогает сохранить естественный порядок времени, когда новые данные должны оказаться в начале списка.

Добавление нескольких значений сразу

const numbers = [3, 4, 5];
numbers.unshift(1, 2);

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

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

Особенности и ограничения

Методы изменяют исходный массив

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

Если массив нужно сохранить в исходном виде, стоит заранее сделать копию:

const original = ['a', 'b', 'c'];
const copy = original.slice();

copy.shift();

console.log(original); // ['a', 'b', 'c']
console.log(copy);     // ['b', 'c']

Удобство vs производительность

Для небольших массивов разница обычно несущественна. Но при больших объёмах данных повторяющееся использование shift() и unshift() может быть менее эффективным, чем операции с концом массива. Причина в том, что при изменении начала массива многие элементы приходится переиндексировать.

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

затраты ≈ количество перемещаемых элементов

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

Сравнение с push и pop

Часто shift/unshift сравнивают с pop/push. У них похожая логика, но противоположная сторона массива:

  • pop() удаляет последний элемент;
  • push() добавляет элемент в конец;
  • shift() удаляет первый элемент;
  • unshift() добавляет элемент в начало.

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

Практические нюансы работы с кодом

Проверка результата shift()

Поскольку shift() возвращает удалённый элемент, его часто удобно использовать прямо в присваивании:

const items = [10, 20, 30];
const firstItem = items.shift();

if (firstItem !== undefined) {
  console.log('Удалён:', firstItem);
}

Если массив может быть пустым, полезно учитывать, что результатом станет undefined. Это особенно важно в условиях и циклах.

Проверка длины после unshift()

Метод unshift() возвращает новую длину массива. Иногда это удобно, если нужно сразу понять, сколько элементов теперь хранится в коллекции:

const arr = [2, 3];
const newLength = arr.unshift(1);

console.log(newLength); // 3

Однако в большинстве случаев длину можно прочитать и через arr.length, поэтому возвращаемое значение используется не всегда.

Работа с массивами и ссылками

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

const a = [1, 2, 3];
const b = a;

b.shift();

console.log(a); // [2, 3]
console.log(b); // [2, 3]

Этот момент нередко становится источником ошибок, если не учитывать, что массив не копируется автоматически.

Типичные ошибки при использовании

  • Ожидание, что метод вернёт новый массив, хотя на самом деле он изменяет исходный.
  • Забывание, что shift() возвращает элемент, а не массив.
  • Предположение, что unshift() добавляет только одно значение, хотя можно передать несколько.
  • Использование shift() в очень больших массивах без учёта возможной нагрузки.
  • Игнорирование того, что индексы всех элементов после начала массива меняются.

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

Когда лучше выбирать другие подходы

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

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

Сводная таблица для запоминания

Ситуация Подходящий метод Почему
Нужно удалить первый элемент и получить его значение shift() Метод удаляет начало массива и возвращает удалённый элемент
Нужно добавить элемент в начало unshift() Метод вставляет значение перед всеми существующими элементами
Нужно добавить несколько элементов в начало unshift() Метод принимает несколько аргументов
Нужно сохранить массив без изменений Ни один из этих методов напрямую Оба метода мутируют массив, поэтому сначала нужна копия

Итог

Shift() и unshift() — простые, но очень важные методы массивов в JavaScript. Первый удаляет элемент с начала и возвращает его, второй добавляет один или несколько элементов в начало и возвращает новую длину. Оба метода изменяют исходный массив, сдвигают индексы и могут быть менее удобны при больших объёмах данных, если операции выполняются слишком часто.

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

FAQ

Почему shift() и unshift() могут быть заметно медленнее на больших массивах?
Оба метода работают не с концом, а с началом массива, поэтому после операции часто приходится сдвигать множество элементов и пересчитывать их индексы. Для маленьких коллекций это обычно незаметно, но при больших объёмах данных одна такая операция затрагивает уже не один элемент, а значительную часть массива.

Из-за этого повторяющееся использование shift() и unshift() может стать дорогим по времени в циклах, очередях с большим числом записей или при частом обновлении списка. На практике это означает, что код может оставаться правильным, но начинать работать ощутимо медленнее. Если операции с началом выполняются постоянно, лучше заранее оценить, действительно ли массив — подходящая структура для такого сценария.
Что будет с индексами элементов после shift() и unshift()?
После shift() все элементы, которые стояли правее первого, сдвигаются на одну позицию влево. Это значит, что элемент с индексом 1 становится новым элементом с индексом 0, элемент с индексом 2 — с индексом 1 и так далее. В результате изменяется не только содержимое массива, но и положение каждого оставшегося элемента.

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

Такое поведение позволяет писать более простой код без дополнительных проверок перед каждым вызовом. Но если результат нужен для дальнейшей логики, важно помнить, что undefined в этом случае означает не ошибку, а отсутствие элемента. Поэтому при обработке данных полезно различать пустой массив и реальное значение, которое может быть ложно интерпретировано.
Возвращают ли shift() и unshift() одинаковый результат?
Нет, эти методы возвращают разные вещи. shift() возвращает удалённый первый элемент массива, то есть само значение, которое было извлечено из начала. unshift(), наоборот, возвращает новую длину массива после добавления элементов в начало.

Это различие особенно важно в коде, где результат вызова сразу используется в переменной. Если ожидается элемент, а вместо этого получена длина, логика может сломаться незаметно. Поэтому при работе с этими методами стоит помнить: shift() — про извлечение значения, unshift() — про изменение размера массива.
Почему shift() и unshift() изменяют исходный массив, а не создают новый?
Эти методы относятся к мутирующим операциям: они изменяют массив прямо на месте. Это означает, что после вызова меняется сам исходный объект, а не его копия. Такой подход удобен, когда нужно быстро обновить существующую коллекцию без создания нового массива на каждый шаг.

Однако у этого есть побочный эффект: если тот же массив используется в нескольких местах программы, изменение затронет все ссылки на него. Чтобы сохранить исходные данные, перед применением метода обычно делают копию, например через slice(). Это особенно полезно, когда нужно сравнивать старое и новое состояние или избегать неожиданных изменений в соседних частях кода.
Когда лучше использовать shift(), а когда unshift() в очереди?
Если задача построена по принципу FIFO, то shift() удобно использовать для извлечения первого пришедшего элемента из начала очереди. Это соответствует естественной логике очереди: сначала добавили — первым обработали. Такой подход хорошо подходит для задач, сообщений, событий и других последовательностей, где важен порядок поступления.

unshift() полезен в другой ситуации: когда нужно срочно поставить элемент в начало списка, чтобы он оказался обработан раньше остальных. Это может быть полезно для приоритетных записей или временного изменения порядка. Но если таких операций много, стоит помнить о возможной нагрузке на производительность, потому что каждый вызов сдвигает существующие элементы.
Можно ли добавить сразу несколько элементов через unshift()?
Да, unshift() умеет добавлять сразу несколько значений в начало массива за один вызов. При этом новые элементы вставляются в том порядке, в котором они перечислены в аргументах, а все старые значения сдвигаются вправо. Это удобно, когда нужно сразу подготовить несколько первых элементов без нескольких отдельных операций.

Такой способ делает код компактнее и понятнее, особенно если новые данные уже собраны заранее. Кроме того, одна операция обычно удобнее нескольких подряд, потому что её проще читать и она явно показывает намерение: не просто добавить элемент, а сразу расширить начало массива целым блоком.
Стоит ли сохранять массив через копию перед shift() или unshift()?
Если исходный массив ещё понадобится в первоначальном виде, копия перед операцией — хороший выбор. Поскольку оба метода изменяют массив на месте, без копии вы потеряете исходное состояние. Это особенно важно, когда массив используется как источник данных, а результат нужен только для локальной обработки.

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

Похожие страницы