자바스크립트 배열 뒤집기: reverse()와 toReversed() 함수

자바스크립트 배열 뒤집기: reverse()와 toReversed() 함수

자바스크립트로 코딩하다 보면 배열의 순서를 뒤집어야 할 때가 종종 있죠? 최신 데이터를 먼저 보여줘야 하는 타임라인이나, 정렬 순서를 반대로 바꿔야 하는 상황처럼요.

이럴 때 예전부터 있었던 reverse() 함수를 사용하면 간단히 해결되는데, 이 함수에는 한 가지 까다로운 점이 숨어 있습니다. 바로 원본 배열을 직접 변경해버린다는 건데요.

이번 글에서는 기존의 reverse() 함수가 왜 문제가 될 수 있는지 살펴보고 비교적 최근에 추가된 toReversed() 함수로 안전하게 배열을 뒤집는 방법을 알아보겠습니다.

배열의 reverse() 함수

자바스크립트에서 배열의 순서를 뒤집는 가장 전통적인 방법은 reverse() 함수입니다.

[1, 2, 3, 4, 5].reverse();
// [5, 4, 3, 2, 1]

문자열 배열도 마찬가지로 동작합니다.

["a", "b", "c", "d"].reverse();
// ['d', 'c', 'b', 'a']

사용법 자체는 정말 직관적이죠? 그런데 reverse() 함수에는 반드시 알아둬야 할 중요한 특징이 있습니다.

reverse()는 원본을 바꾼다

reverse() 함수는 새로운 배열을 만들어서 반환하는 게 아니라 원래 배열의 원소를 제자리에서 재배치합니다.

const nums = [1, 2, 3, 4, 5];
const reversed = nums.reverse();
console.log({ nums, reversed });
결과
{
  nums: [5, 4, 3, 2, 1],
  reversed: [5, 4, 3, 2, 1]
}

numsreversed가 완전히 같은 배열이 되어버렸습니다. 실제로 둘은 같은 객체를 가리키고 있거든요.

nums === reversed; // true

이게 왜 문제가 되냐면, 원본 데이터를 그대로 유지해야 하는 상황에서 의도치 않은 버그를 만들 수 있기 때문입니다.

원본 변경이 위험한 경우

실무에서 흔히 겪는 상황을 하나 살펴보겠습니다.

예를 들어, 서버에서 받은 할 일 목록을 원래 순서와 역순 두 가지로 보여줘야 한다고 가정해볼게요.

const todos = [
  { id: 1, text: "장보기" },
  { id: 2, text: "운동하기" },
  { id: 3, text: "책 읽기" },
];

// 최신 순으로 보여주고 싶어서 뒤집음
const recent = todos.reverse();

console.log(recent);
// [{ id: 3, ... }, { id: 2, ... }, { id: 1, ... }] ✅ 의도한 대로

console.log(todos);
// [{ id: 3, ... }, { id: 2, ... }, { id: 1, ... }] 😱 원본도 바뀜!

reverse()를 호출한 순간 todos 배열도 함께 뒤집어져 버렸습니다. 원래 순서로 보여주고 싶을 때 이미 원본이 변경된 상태라 곤란해지죠.

이 문제를 피하려면 reverse()를 호출하기 전에 배열을 복제해야 합니다.

const recent = [...todos].reverse();

스프레드 연산자(...)로 사본을 만든 다음 그 사본을 뒤집는 건데요. 동작은 하지만 매번 이렇게 작성하는 게 번거롭기도 하고, 무엇보다 복제하는 걸 깜빡하면 바로 버그가 됩니다.

배열의 toReversed() 함수

바로 이런 불편함을 해결하기 위해 자바스크립트에 toReversed() 함수가 추가되었습니다.

toReversed() 함수는 원본 배열은 그대로 두고, 순서가 뒤집어진 새 배열을 반환합니다.

const nums = [1, 2, 3, 4, 5];
const reversed = nums.toReversed();
console.log({ nums, reversed });
결과
{
  nums: [1, 2, 3, 4, 5],
  reversed: [5, 4, 3, 2, 1]
}

nums는 원래 그대로이고, reversed에만 뒤집어진 배열이 담겨 있죠? 당연히 두 배열은 서로 다른 객체입니다.

nums === reversed; // false

아까 그 할 일 목록 예제도 toReversed()를 쓰면 훨씬 깔끔해집니다.

const todos = [
  { id: 1, text: "장보기" },
  { id: 2, text: "운동하기" },
  { id: 3, text: "책 읽기" },
];

const recent = todos.toReversed();

console.log(recent);
// [{ id: 3, ... }, { id: 2, ... }, { id: 1, ... }] ✅

console.log(todos);
// [{ id: 1, ... }, { id: 2, ... }, { id: 3, ... }] ✅ 원본 그대로!

배열을 복제할 필요도 없고, 원본이 바뀔 걱정도 없습니다.

[…arr].reverse() vs toReversed()

toReversed()가 없던 시절에는 [...arr].reverse() 패턴을 많이 썼는데요. 이제는 toReversed()를 쓰는 편이 여러모로 낫습니다.

우선 코드가 간결해지고 의도가 명확해지죠.

// 예전 방식
const reversed = [...nums].reverse();

// 요즘 방식
const reversed = nums.toReversed();

메서드 체이닝에서도 자연스럽게 사용할 수 있습니다.

const result = items
  .filter((item) => item.active)
  .toReversed()
  .map((item) => item.name);

[...arr].reverse() 패턴을 체이닝 중간에 끼워 넣으려면 코드가 좀 어색해지는 반면 toReversed()는 다른 배열 함수와 같은 형태로 이어서 호출할 수 있습니다.

다른 불변 배열 메서드들

toReversed()는 혼자 등장한 게 아닙니다. 자바스크립트에서는 원본 배열을 변경하는 기존 메서드에 대응하는 불변 버전이 함께 추가되었는데요.

원본 변경 (기존)원본 유지 (신규)하는 일
reverse()toReversed()배열 뒤집기
sort()toSorted()배열 정렬
splice()toSpliced()배열 잘라내기/교체
arr[i] = vwith(i, v)특정 인덱스 값 교체

이 메서드는 모두 같은 철학을 공유합니다. 원본은 건드리지 않고 결과만 새 배열로 돌려준다는 거죠.

배열 정렬: sort()와 toSorted() 함수에서 toSorted()에 대해 자세히 다뤘으니, 정렬 쪽이 궁금하시면 참고해 보세요. slice()와 splice() 함수도 함께 읽어보시면 배열을 자르고 교체하는 기존 방식의 문제점을 이해하는 데 도움이 될 겁니다.

브라우저 지원

toReversed() 함수는 2023년 중반부터 대부분의 모던 브라우저에서 사용할 수 있습니다. Chrome 110, Firefox 115, Safari 16, Edge 110 이상이면 문제없이 동작하고요. Node.js에서는 v20부터 지원됩니다.

인터넷 익스플로러에서는 당연히 사용할 수 없지만, 2026년 현재 IE를 지원해야 하는 프로젝트는 거의 없을 테니 대부분의 경우 안심하고 쓸 수 있겠습니다.

마치며

지금까지 자바스크립트에서 배열을 뒤집을 때 쓰는 reverse() 함수와 toReversed() 함수를 살펴봤습니다.

reverse()는 원본 배열을 직접 변경하기 때문에 의도치 않은 부작용을 만들 수 있고 toReversed()는 원본을 그대로 둔 채 새 배열을 반환하니까 훨씬 안전합니다. 새로 코드를 작성할 때는 원본 변경이 꼭 필요한 게 아니라면 toReversed()를 우선 사용하는 습관을 들이면 좋겠습니다.

자바스크립트의 배열 함수에 대해 좀 더 알고 싶으시다면 배열의 원소 추가하기: push()와 unshift()배열의 원소 제거하기: pop()와 shift()도 참고해 보세요.

This work is licensed under CC BY 4.0 CC BY

개발자를 위한 뉴스레터

달레가 정리한 AI 개발 트렌드와 직접 만든 콘텐츠를 전해드립니다.

Discord