
JavaScript에서 배열을 처음 배울 때 '배열은 계속 값이 바뀌는데 .. const로 선언하면 안 되는 거 아닌가?' 라는 고민이 생겼었다.
그리고 결론부터 말하자면, 배열은 let과 const 둘 다로 선언할 수 있으며, 심지어 오히려 배열을 const로 선언하는 경우가 더 많다고 한다.
이게 가능한 이유는 let과 const가 배열이 변하느냐를 기준으로 동작하는 게 아니라, `변수가 무엇을 가리키는지(= 참조하는지)를 다시 바꿀 수 있느냐(= 재할당이 가능하냐)`를 기준으로 동작하기 때문이다.
1. 배열
배열은 보통 아래와 같이 쓰는데, 마치 숫자들을 넣어논 상자 같은 느낌이다.
const arr = [1, 2, 3];
그러나 JavaScript에서 배열은 원시값이 아니라 객체임에 주의해야 한다.
즉, 아래와 같이 배열의 타입을 찍어보면 "object"라는 결과가 나오게 된다.
console.log(typeof [1, 2, 3]); // object
이러한 결과는 변수 arr 안에 [1, 2, 3]이 통째로 들어있는 게 아니라, 메모리 어딘가에 만들어져 있는 배열을 가리키는 주소를 들고있음을 잘 보여준다.
좀 더 비유해서 표현하자면, 이 예시에서 선언한 arr은 배열 자체가 아니라, 배열을 가리키는 화살표에 가깝다.
그리고 이 화살표를 다른 배열을 가리키게 바꿀 수 있느냐 없느냐가 let과 const의 차이이기도 하다.
2. let으로 선언한 배열
let은 변수가 가리키는 대상을 다른 것으로 바꿔 끼우는 것, 즉, 재할당이 가능하다.
따라서 아래 예시와 같이 배열 내부 값도 변경 가능하고, 다른 배열로 아예 재할당하는 것도 가능한 것이다.
let arr = [1, 2, 3];
arr.push(4); // 배열에 새로운 값 추가 가능
arr[0] = 100; // 배열 내부의 값 변경 가능
arr = [9, 9, 9]; // 다른 배열로 재할당 가능
또한, 여기서 중요한 점이 push나 `arr[0] = 100`은 변수 재할당이 아니라 배열 내부를 수정하는 거라는 점이다.
즉, let으로 선언한 배열은 내부 수정도 가능하고, 변수가 가리키는 배열 자체를 아예 다른 배열을 재할당 하는 것도 가능하다고 보면 된다.
3. const로 선언한 배열
반대로, const는 변수가 가리키는 대상을 다른 것으로 재할당하는 것이 금지된다.
즉, 아까와 똑같은 예시에서 배열 선언만 const로 바꾼다면, 마지막 줄에서는 에러가 발생하게 되는 것이다.
const arr = [1, 2, 3];
arr.push(4); // 배열에 새로운 값 추가 가능
arr[0] = 100; // 배열 내부의 값 변경 가능
arr = [9, 9, 9]; // TypeError 발생 !!
재할당이 안 되니까 마지막 줄이 에러가 나는 건 알겠는데, 왜 push와 `arr[0] = 100`은 잘 실행되는 걸까?
앞서 슬쩍 말했듯이 const가 금지하는 건 재할당이지, 변경이 아니기 때문이다.
따라서 이 변수가 가리키는 대상 자체를 변경하는 마지막 줄에서는 에러가 발생하지만, 그냥 배열 내부의 값을 변경하는 push와 `arr[0] = 100`에서는 에러가 발생하지 않는 것이다.
4. let보다 const 배열을 자주 사용하는 이유
const라는 건 재할당을 금지하지만, 변경 자체는 허락한다 했다.
예를 들어 아래와 같이 const로 선언된 users라는 배열을 생각해보자.
const users=[];
users.push("ssosso");
users.push("ttotto");
이건 '이 배열 자체는 계속 users로 유지 될건데, 대신 그 안에 값은 추가하거나 삭제하는 등 변경이 가능해!' 라는 의미를 갖는다.
반면, users를 let으로 선언했다면 '이건 나중에 users 말고 다른 걸 담을수도?' 라는 의미이기 때문에 실제로 다른 배열로 의도적으로 바꿀 계획이 있는 게 아니라면 let 보다는 const가 훨씬 안전하고 읽기 좋은 기본값이 된다.
5. let 배열을 사용하는 경우
물론 그렇다 해서 let 배열을 사용하지 않는 건 아니다.
배열 내부가 아니라, 변수가 가리키는 배열 자체를 바꾸어야 할 때에는 당연히 let을 사용해주어야 하는데, 이 또한 생각보다 우리가 본 적이 있는 케이스들이 꽤나 있을 것이다.
예를 들어, 아래와 같은 코드를 살펴보자.
let result = [];
if (isAdmin) {
result = users.filter(u => u.role === "admin");
} else {
result = users.filter(u => u.role === "user");
}
여기서는 result가 상황에 따라 완전히 다른 배열로 바뀌는 게 개발자의 의도이기 때문에 let을 사용하는 게 너무나도 당연하다.
6. 배열을 직접 수정하는 메서드와 새 배열을 만들어서 반환하는 메서드
배열을 직접 수정하는 메서드들(mutable)은 아래와 같은 것들이 있다.
- push
- pop
- shift
- unshift
- splice
- sort
- reverse
이러한 것들은 const를 사용해도 된다.
왜냐하면 재할당을 하는 게 아니라 배열을 직접 수정하는 것이기 때문이다.
반대로, 새 배열을 만들어서 반환하는 메서드들(immutable)은 아래와 같은 것들이 있다.
- map
- filter
- slice
- concat
이러한 것들은 새 배열을 반환하는 것이기 때문에 반드시 그 결과를 담아줄 변수가 필요하다.
'👩🏻💻 Frontend > 📌 JavaScript' 카테고리의 다른 글
| [JavaScript] 데이터 타입 (undefined, null, number, object 등) (0) | 2026.02.05 |
|---|---|
| [JavaScript] 이벤트 (addEventListener, 이벤트 버블링, 이벤트 위임 등) (0) | 2026.02.04 |
| [JavaScript] 문서 객체 선택 (0) | 2026.02.04 |
| [JavaScript] 콜백 함수 (0) | 2026.02.04 |
| [JavaScript] let과 const (0) | 2026.02.03 |