![Array[index] 사용을 그만둬라 애송이](https://w.wallhaven.cc/full/d5/wallhaven-d5gz5g.jpg)
이 포스트는 Timotius Sitorus가 자신의 dev.to 블로그에 올린 Stop using Array[index], use Array.at() instead 게시글을 번역한 것이다. 번역하는 과정에서 다소 의역이 있을 수 있으며, 일부 번역에는 사견이 포함되어있기도 하다.
Array.at() 메소드는 ECMAscript2022를 통해 새롭게 추가된 Array 생성자의 프로토타입 메소드입니다. 이 메소드를 통해 우리는 마침내 JS에서 기본적으로 Negative Indexing을 처리할 수 있게 되었습니다.
Negative Indexing
네거티브 인덱싱이라 함은 음수를 인덱스로 사용하여 배열의 시작이 아닌 끝에서부터 특정 요소에 엑세스하는 기능입니다. 예를 들어 파이썬에서는 배열의 마지막 요소에 접근하고 싶은 경우 list[-1]과 같은 방식으로 작업을 수행할 수 있습니다.
그러나 JS의 array는 이런 식으로 작동하지 않습니다. 대괄호 표기법이 array나 string에 속한 것이 아니라 모든 object에 속하기 때문에 ─ 이 부분에 대해서 따로 확인해본 것은 아니지만 이러한 표기법을 지원하는 프로퍼티가 object 생성자의 prototype에 존재하는 것이 아닐까 추측한다 ─ 그렇습니다.
object에서 대괄호 표기법을 사용할 경우 해당 key를 사용하여 객체의 value를 얻는 것을 의미합니다. 배열과 문자열 역시 객체이기 때문에, 이러한 자료형들에서도 동일한 작동을 보이는 것입니다. 내부적으로 배열과 문자열은 각 요소를 현재 인덱스와 일치하는 키에 할당합니다.
// 인덱싱 방식에 관해서라면 arr는 obj와 완전히 동일하게 동작한다
const arr = ['cat', 'dog', 'fish', 'bird'];
const obj = {
0: 'cat',
1: 'dog',
2: 'fish',
3: 'bird'
};따라서 arr[-1]은 이미 유효한 JS이지만 마지막 요소를 반환하는 것이 아닌 배열의 "-1" key에 해당하는 value를 반환하려고 시도합니다. 그리고 이러한 경우 JS는 당연하게도 ─ "-1" key가 없으니 ─ undefined를 반환하게 될 것입니다.
기존의 해결 방법
기존 JS에서는 네거티브 인덱싱을 지원하지 않지만, 이를 흉내내는 기법 몇 가지가 널리 알려져있습니다. 아마도 가장 유명한 기법은 배열의 길이에서 음수 인덱스만큼 뺀 값을 사용하는 것입니다.
const pets = ['cat', 'dog', 'fish', 'bird'];
const lastPet = pets[pets.length - 1];
console.log(lastPet); // Prints out 'bird'대부분의 개발자가 네거티브 인덱싱을 흉내내기 위해 사용하는 기법이지만, 여기에는 몇 가지 문제가 있습니다.
배열의 이름이 두 번 호출되며, 일반적으로는 꽤 길어집니다.
변수에 할당되지 않은 배열에는 사용할 수 없습니다.
임시 변수에 저장하지 않는 한 함수가 리턴하는 마지막 값을 쓸 수 없습니다.
['cat', 'dog', 'fish', 'bird'][ **what do you put here** - 1];
const a = () => ['cat', 'dog', 'fish', 'bird'];
a()[ **What do you out here** - 1];다른 방식으로는 Array.slice() 메소드가 네거티브 인덱싱을 지원한다는 점을 이용할 수 있습니다.
const pets = ['cat', 'dog', 'fish', 'bird'];
const lastPet = pets.slice(-1)[0];
console.log(lastPet); // Prints out 'bird'이 방법은 앞서 언급한 많은 문제를 해결하지만, 몇 가지 새로운 문제를 일으킵니다.
구문을 직관적으로 이해하는 데 어려움이 있습니다. 특히 네거티브 인덱싱으로 slice된 array에 [0]이 꼬리를 물고 붙어있다는 점이 그렇습니다.
지정한 인덱스로부터 배열의 끝까지가 임시 배열을 이루게 됩니다. 이는 [0]을 통해 원하는 item을 리턴한 이후 메모리 힙에서 즉시 삭제됩니다.
Array.at()
at 메소드는 위에서 언급한 다양한 문제를 해결하기 위해 구현되었습니다. 아규먼트로 양수를 넣을 경우 Array[index]와 정확히 동일한 작동을 보장하면서, 아규먼트로 음수를 넣는 경우에는 네거티브 인덱싱을 완벽하게 구현해냅니다.
const pets = ['cat', 'dog', 'fish', 'bird'];
const lastPet = pets.at(-1);
console.log(lastPet); // Prints out 'bird'이 메소드를 사용하므로써 네거티브 인덱싱을 흉내내는 이전의 방식들을 대체할 수 있으며, 더 깔끔한 구문을 제공하며, 성능 저하가 발생하지도 않습니다. 필요한 경우 polyfill을 사용할 수 있으며, 대부분의 최신 브라우저에서 at 메소드를 사용할 수 있습니다.
더 읽어보기
2026.03.13
Streams API 3. 바이트 스트림과 실전 파이프라인
앞선 두 글에서 우리는 Web Streams API의 표면과 의미론을 정리했다. 이제 남은 질문은 하나이다. 이 지식을 실제 어디에 써먹을 것인가. 이 질문에 답하는 순간 스트림 학습은 비로소 완성된다. 표준을 읽고 메서드를 아는 것만으로는 충분하지 않다. fetch() 응답 본문을 어…
2026.03.13
Streams API 2. 상태와 백프레셔의 의미론
스트림을 처음 배울 때는 읽고 쓰는 예제가 꽤 단순해 보인다. getReader()로 읽고, getWriter()로 쓰고, pipeTo()로 연결하면 끝나는 것처럼 느껴진다. 실제로 짧은 데모는 이 정도만 알아도 돌아간다. 그러나 실무에서 스트림 코드를 망가뜨리는 원인은 거의 언제나 더…
2026.03.13
Streams API 1. 읽기와 쓰기의 출발점
자바스크립트에서 비동기를 배울 때 우리는 대개 Promise와 async, await부터 익힌다. 이 조합은 한 번의 결과를 기다리는 문제에는 매우 강력하다. 그러나 데이터가 한 번에 끝나지 않고 계속 흘러들어오는 상황에서는 이야기가 달라진다. 네트워크 응답이 길게 이어지거나, 큰 파일…
2026.03.04
JavaScript를 위한 더 나은 Streams API가 필요하다
이 포스트는 node.js의 코어 컨트리뷰트이며 Cloudflare Workers 팀 소속 개발자 James M Snell이 cloudflare 블로그에 올린 We deserve a better streams API for JavaScript 게시글을 번역한 것이다. 번역하는 과정에서…
2026.04.11
Trie 자료구조
문자열 데이터를 다룰 때 단순히 “이 단어가 있나?”만으로는 부족한 순간이 있다. 자동 완성처럼 특정 접두사로 시작하는 후보를 모아야 할 때도 있고, 어떤 키에 값을 두고 빠르게 찾고 싶을 때도 있다. 이럴 때 가장 자연스럽게 떠올릴 수 있는 자료구조가 바로 Trie이다.Trie는 무엇…
2026.03.19
Streams API 부록 2. 왜 이미지는 위에서 아래로 나타날까
웹 페이지에서 이미지를 로드할 때 흥미로운 장면을 종종 볼 수 있다. 이미지가 한 번에 완전히 나타나는 것이 아니라, 위에서 아래로 조금씩 채워지면서 나타나는 경우가 있기 때문이다. 특히 네트워크가 느리거나 이미지가 큰 경우 이런 현상이 더 분명하게 보인다. 마치 이미지가 위쪽부터 스캔…
2026.03.19
Streams API 부록 1. HTTP 다운로드 진행률은 어떻게 계산될까
파일을 다운로드할 때 가끔 몇 퍼센트 진행되었는지 혹은 진행 막대(progress bar)가 조금씩 채워지는 모습을 볼 수 있다. 그런데 모든 다운로드가 이런 식으로 진행률을 보여 주는 것은 아니다. 어떤 다운로드는 퍼센트가 표시되지만, 어떤 경우에는 진행 막대 없이 로딩 스피너만 계속…
2026.03.13
Streams API 4. 왜 모든 언어에는 Stream API가 존재할까
Streams API를 공부하다 보면 묘한 기시감을 느끼게 된다. JavaScript에서 ReadableStream, WritableStream, TransformStream을 살펴보고 있는데, 어딘가 낯설지 않다. Java를 써 본 사람이라면 InputStream, OutputStre…
댓글
댓글을 불러오는 중...