배열


장바구니, 성적 목록, 단체 채팅방에 있는 모든 사람의 이름을 다뤄야 하는 상황을 생각해봅시다. 변수 하나에는 값 하나만 담기기 때문에, 이런 목록을 이 방식으로 저장하면 price1, price2, price3처럼 이름이 따로따로 늘어나기만 하고, 이를 반복 처리하거나 개수를 물어볼 깔끔한 방법이 없습니다. 배열이 바로 이 문제를 해결해줍니다. 배열은 여러 값을 순서대로 하나의 이름 아래 담아두며, 자기 길이를 스스로 알고 있어서 값을 추가하고, 원하는 항목을 읽고, 전체를 몇 줄로 순회할 수 있습니다.
배열 만들고 읽기
**배열**은 값들을 순서대로 담은 목록입니다. 대괄호를 사용해서 만들며, 값은 쉼표로 구분합니다:
const prices = [4, 9, 2, 7];이건 prices라는 변수 하나에 숫자 네 개가 담긴 것입니다. 하나의 값을 읽으려면 그 위치, 즉 인덱스를 대괄호에 넣어 사용합니다. 처음 배우는 사람들이 거의 다 걸려 넘어지는 부분이 있는데, 개수는 0부터 셉니다, 1부터가 아닙니다.
const names = ["마라", "쿠아메", "유키"];
console.log(names[0]); // 마라
console.log(names[1]); // 쿠아메배열에 항목이 몇 개 있는지 알려면 .length를 사용합니다:
console.log(names.length); // 30부터 세기 때문에 마지막 항목은 length가 아니라 length - 1에 있습니다. 그래서 여기서 마지막 이름은 names[2]이고, names[3]은 범위를 벗어난 값입니다.
names[0]처럼 위치로 항목을 읽고, 개수는 0부터 센다는 걸 기억하세요. 그래서 첫 번째 항목은 [1]이 아니라 [0]입니다. 이 0부터 세는 방식 때문에 일주일 동안 헤맸으니, 목록이 하나씩 어긋난다면 이 부분을 먼저 확인하세요. 항목 개수는 .length로 세고, 마지막 항목은 length - 1에 있습니다. 배열 바꾸기
배열은 원래 바뀌도록 만들어져 있습니다. 가장 많이 쓰는 두 메서드는 끝에서 추가하거나 제거합니다. push는 항목을 추가하고, pop은 마지막 항목을 제거합니다.
const cart = ["사과", "빵"];
cart.push("우유");
console.log(cart); // ["사과", "빵", "우유"]
cart.pop();
console.log(cart); // ["사과", "빵"]짝을 이루는 메서드는 앞에서 작동합니다. unshift는 맨 앞에 추가하고, shift는 첫 번째 항목을 제거합니다.
cart.unshift("계란");
console.log(cart); // ["계란", "사과", "빵"]인덱스에 직접 할당해서 항목을 바꿀 수도 있습니다:
cart[0] = "바나나";
console.log(cart); // ["바나나", "사과", "빵"]무언가를 찾을 때는 includes가 있는지 없는지 알려주고, indexOf는 그 위치를 알려줍니다(없으면 -1을 줍니다):
console.log(cart.includes("사과")); // true
console.log(cart.indexOf("빵")); // 2일찍 알아두면 좋은 게 하나 있습니다. const로 선언한 배열도 여전히 바꿀 수 있습니다. const는 cart라는 이름을 완전히 새로운 배열로 다시 지정하는 것만 막을 뿐이고, 그 이름이 가리키는 목록 자체는 push, pop, 인덱스 할당으로 여전히 자유롭게 바꿀 수 있습니다.
push와 pop은 끝에서 추가하고 제거하며, unshift와 shift는 앞에서 똑같이 동작합니다. cart[0] = "바나나"처럼 인덱스에 값을 할당해서 항목을 바꿀 수 있고, 무언가를 찾으려면 includes나 indexOf를 쓰세요. 저를 놀라게 한 부분은, const로 선언한 배열도 여전히 바뀔 수 있다는 점이었습니다. const는 배열 전체를 새 배열로 바꿔치기하는 것만 막을 뿐입니다. 배열 순회하기
목록이 있으면 보통 그 안의 모든 항목에 대해 어떤 작업을 하고 싶어집니다. 배열을 읽어나가는 가장 깔끔한 방법은 for...of이며, 한 번에 항목 하나씩 건네줍니다:
const prices = [4, 9, 2, 7];
for (const price of prices) {
console.log(price);
}
// 4
// 9
// 2
// 7인덱스나 카운터를 따로 관리할 필요가 없습니다. for...of는 순서대로 각 값을 건네주고, 이름(price)은 원하는 대로 붙이면 됩니다. 반복문을 이미 배웠다면, 배열을 다룰 때 이게 가장 친숙한 방법입니다.
forEach도 있는데, 이건 각 항목마다 작은 함수를 한 번씩 실행합니다:
const names = ["마라", "쿠아메", "유키"];
names.forEach(function (name) {
console.log("안녕 " + name);
});둘 다 배열 전체를 순회합니다. 깔끔하게 읽어나가고 싶을 때는 for...of를 쓰고, 배열을 변형하는 법을 배울 때 forEach와 그 친척들을 다시 만나게 됩니다.
for...of는 배열을 순회하는 깔끔한 방법입니다. 각 항목을 순서대로 건네주고, 인덱스를 직접 다룰 일이 없습니다. forEach는 항목마다 작은 함수를 한 번씩 실행하는데, 이것도 유용합니다. 둘 다 목록 전체를 훑으므로, 처음부터 끝까지 읽어나가고 싶다면 for...of를 고르세요. 배열을 변형하는 법을 배우면 더 다양한 도구를 만나게 됩니다. 배열은 참조로 전달됩니다
미리 알아두면 놀라지 않을 동작이 하나 있습니다. 배열 변수를 다른 이름에 복사해도 배열이 하나 더 생기는 게 아닙니다. 두 이름 모두 같은 배열을 가리킵니다.
const original = [1, 2, 3];
const copy = original;
copy.push(4);
console.log(original); // [1, 2, 3, 4]copy에 push했는데 original이 바뀌었습니다. 배열이 원래부터 하나뿐이었기 때문입니다. =는 두 번째 이름에게 새로 복사된 목록을 준 게 아니라, 같은 목록을 그대로 준 것입니다. 사람들이 배열이 참조로 전달된다고 말할 때 뜻하는 게 바로 이겁니다. 변수는 목록 자체가 아니라 목록을 가리키는 포인터를 담고 있습니다.
진짜로 독립된 복사본을 만들려면, ...로 배열을 새 배열에 펼쳐 넣으세요:
const original = [1, 2, 3];
const copy = [...original];
copy.push(4);
console.log(original); // [1, 2, 3], 그대로 유지됨=로 배열 변수를 복사해도 배열이 하나 더 생기지 않습니다. 두 이름 모두 같은 배열을 가리키므로, 어느 쪽을 통해 바꿔도 양쪽 모두에서 보입니다. 저도 이것 때문에 여러 번 당했습니다. 진짜로 독립된 복사본이 필요할 때는 [...original]로 펼쳐서 따로 바꿀 수 있는 새 배열을 만드세요. 배열, 그 다음은
배열은 하나의 이름 아래 순서 있는 목록을 담아줍니다. []로 만들고, 0부터 시작하는 인덱스로 읽고, push와 pop으로 바꾸고, for...of로 순회합니다. 이 장을 넘어서도 꼭 기억해둘 한 가지는, 배열이 참조로 전달되기 때문에 변수를 복사하면 목록이 복제되는 게 아니라 공유된다는 점입니다.
자연스러운 다음 단계는 하나의 배열로 다른 배열을 만드는 것, 즉 목록을 걸러내거나 모든 항목을 변형하거나 전부 더하는 작업을 반복문을 직접 짜지 않고 처리하는 방법입니다. 그게 배열 메서드입니다. 위치가 아니라 이름으로 값을 찾아봐야 할 때는 객체가 그 구조를 제공합니다.

