포스트

JavaScript 배열(Array) 완벽 가이드 - 기초부터 고급까지

JavaScript 배열의 기본 개념부터 배열 메서드, 고차 함수, 배열 조작 기법까지 상세히 알아봅니다. map, filter, reduce를 활용한 함수형 프로그래밍과 실전 예제를 마스터합니다.

JavaScript 배열(Array) 완벽 가이드 - 기초부터 고급까지

배열이란?

배열(Array)은 여러 개의 값을 순서대로 저장하는 자료구조입니다. 하나의 변수에 여러 데이터를 담을 수 있어 효율적인 데이터 관리가 가능합니다.

배열의 필요성

1
2
3
4
5
6
7
8
9
10
// ❌ 배열 없이 (비효율적)
let city1 = "서울";
let city2 = "대전";
let city3 = "대구";
let city4 = "부산";
let city5 = "광주";
// ... 수백 개의 변수?

// ✅ 배열 사용 (효율적)
let cities = ["서울", "대전", "대구", "부산", "광주"];

배열의 장점

장점설명
효율성하나의 변수로 여러 값 관리
순서 보장데이터의 순서가 유지됨
반복 처리루프로 쉽게 순회 가능
동적 크기크기를 자유롭게 조절

배열 생성

배열 리터럴 (권장)

1
2
3
4
5
6
7
// 빈 배열
let emptyArray = [];

// 데이터가 있는 배열
let cities = ["서울", "대전", "대구", "부산", "광주", "제주도"];
let kospi = [2062.82, 2053.2, 2045.92, 2058.82, 2053.12, 2055.7];
let mixed = ["텍스트", 123, true, null];

Array 생성자

1
2
3
4
5
6
7
8
9
10
11
// 빈 배열
let arr1 = new Array();

// 길이가 5인 빈 배열
let arr2 = new Array(5);
console.log(arr2);        // [empty × 5]
console.log(arr2.length); // 5

// 요소를 지정한 배열
let arr3 = new Array(1, 2, 3);
console.log(arr3);  // [1, 2, 3]

Array.of() (ES6)

1
2
3
// 생성자와 달리 항상 요소로 처리
let arr1 = Array.of(5);      // [5]
let arr2 = Array.of(1, 2, 3); // [1, 2, 3]

배열 요소와 인덱스

요소(Element)

배열의 각 값을 요소(Element)라고 합니다.

1
2
let cities = ["서울", "대전", "대구", "부산", "광주"];
// "서울", "대전", "대구", "부산", "광주" 각각이 요소

인덱스(Index)

배열의 각 요소는 인덱스(Index)라는 위치 번호를 가집니다. 인덱스는 0부터 시작합니다.

1
2
3
4
5
6
let cities = ["서울", "대전", "대구", "부산", "광주"];
//  인덱스:    0      1      2      3      4

console.log(cities[0]);  // "서울"
console.log(cities[1]);  // "대전"
console.log(cities[4]);  // "광주"

요소 접근

1
2
3
4
5
6
7
8
9
10
let numbers = [10, 20, 30, 40, 50];

// 첫 번째 요소
console.log(numbers[0]);  // 10

// 마지막 요소
console.log(numbers[numbers.length - 1]);  // 50

// 존재하지 않는 인덱스
console.log(numbers[10]);  // undefined

요소 수정

1
2
3
4
5
6
7
8
9
let fruits = ["사과", "바나나", "오렌지"];

fruits[1] = "포도";
console.log(fruits);  // ["사과", "포도", "오렌지"]

// 존재하지 않는 인덱스에 할당
fruits[5] = "딸기";
console.log(fruits);  // ["사과", "포도", "오렌지", empty × 2, "딸기"]
console.log(fruits.length);  // 6

배열 길이

1
2
3
4
5
6
7
8
9
10
let cities = ["서울", "대전", "대구", "부산", "광주"];

console.log(cities.length);  // 5

// 길이 변경 (권장하지 않음)
cities.length = 3;
console.log(cities);  // ["서울", "대전", "대구"]

cities.length = 5;
console.log(cities);  // ["서울", "대전", "대구", empty × 2]

다양한 타입의 요소

배열은 어떤 타입의 값도 저장할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let mixed = [
  "문자열",           // String
  123,               // Number
  true,              // Boolean
  null,              // null
  undefined,         // undefined
  { name: "홍길동" }, // Object
  [1, 2, 3],         // Array (중첩 배열)
  function() {}      // Function
];

console.log(mixed[0]);  // "문자열"
console.log(mixed[5]);  // { name: "홍길동" }
console.log(mixed[6]);  // [1, 2, 3]

중첩 배열 (다차원 배열)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let anything = ["대전", 1987, ["하나", "", 3]];

console.log(anything[0]);     // "대전"
console.log(anything[1]);     // 1987
console.log(anything[2]);     // ["하나", "둘", 3]
console.log(anything[2][0]);  // "하나" (중첩 배열의 첫 번째 요소)
console.log(anything[2][2]);  // 3

// 2차원 배열
let matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

console.log(matrix[0][0]);  // 1
console.log(matrix[1][2]);  // 6
console.log(matrix[2][1]);  // 8

배열 메서드

요소 추가/제거

push() - 끝에 추가

1
2
3
4
5
6
7
8
9
10
11
12
let fruits = ["사과", "바나나"];

fruits.push("오렌지");
console.log(fruits);  // ["사과", "바나나", "오렌지"]

// 여러 개 추가
fruits.push("포도", "딸기");
console.log(fruits);  // ["사과", "바나나", "오렌지", "포도", "딸기"]

// 반환값: 새로운 배열 길이
let newLength = fruits.push("수박");
console.log(newLength);  // 6

pop() - 끝에서 제거

1
2
3
4
5
let fruits = ["사과", "바나나", "오렌지"];

let removed = fruits.pop();
console.log(removed);  // "오렌지"
console.log(fruits);   // ["사과", "바나나"]

unshift() - 앞에 추가

1
2
3
4
5
6
7
8
let fruits = ["바나나", "오렌지"];

fruits.unshift("사과");
console.log(fruits);  // ["사과", "바나나", "오렌지"]

// 여러 개 추가
fruits.unshift("포도", "딸기");
console.log(fruits);  // ["포도", "딸기", "사과", "바나나", "오렌지"]

shift() - 앞에서 제거

1
2
3
4
5
let fruits = ["사과", "바나나", "오렌지"];

let removed = fruits.shift();
console.log(removed);  // "사과"
console.log(fruits);   // ["바나나", "오렌지"]

배열 조작

slice() - 부분 배열 추출 (원본 유지)

1
2
3
4
5
6
7
8
9
10
11
12
let fruits = ["사과", "바나나", "오렌지", "포도", "딸기"];

let sliced1 = fruits.slice(1, 3);
console.log(sliced1);  // ["바나나", "오렌지"]

let sliced2 = fruits.slice(2);
console.log(sliced2);  // ["오렌지", "포도", "딸기"]

let sliced3 = fruits.slice(-2);
console.log(sliced3);  // ["포도", "딸기"]

console.log(fruits);   // 원본 유지: ["사과", "바나나", "오렌지", "포도", "딸기"]

splice() - 요소 추가/제거 (원본 변경)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let fruits = ["사과", "바나나", "오렌지", "포도"];

// 요소 제거
let removed = fruits.splice(1, 2);
console.log(removed);  // ["바나나", "오렌지"]
console.log(fruits);   // ["사과", "포도"]

// 요소 추가
fruits.splice(1, 0, "딸기", "수박");
console.log(fruits);   // ["사과", "딸기", "수박", "포도"]

// 요소 교체
fruits.splice(1, 2, "블루베리");
console.log(fruits);   // ["사과", "블루베리", "포도"]

concat() - 배열 결합

1
2
3
4
5
6
7
8
9
10
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let arr3 = [7, 8, 9];

let combined = arr1.concat(arr2, arr3);
console.log(combined);  // [1, 2, 3, 4, 5, 6, 7, 8, 9]

// 스프레드 연산자 사용 (ES6)
let combined2 = [...arr1, ...arr2, ...arr3];
console.log(combined2);  // [1, 2, 3, 4, 5, 6, 7, 8, 9]

join() - 문자열로 변환

1
2
3
4
5
6
let fruits = ["사과", "바나나", "오렌지"];

console.log(fruits.join());      // "사과,바나나,오렌지"
console.log(fruits.join(" "));   // "사과 바나나 오렌지"
console.log(fruits.join(" - ")); // "사과 - 바나나 - 오렌지"
console.log(fruits.join(""));    // "사과바나나오렌지"

reverse() - 순서 뒤집기 (원본 변경)

1
2
3
4
let numbers = [1, 2, 3, 4, 5];

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

sort() - 정렬 (원본 변경)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 문자열 정렬
let fruits = ["바나나", "사과", "오렌지"];
fruits.sort();
console.log(fruits);  // ["바나나", "사과", "오렌지"]

// 숫자 정렬 (주의!)
let numbers = [10, 5, 40, 25, 100];
numbers.sort();
console.log(numbers);  // [10, 100, 25, 40, 5] (문자열로 정렬됨)

// 숫자 올바르게 정렬
numbers.sort((a, b) => a - b);
console.log(numbers);  // [5, 10, 25, 40, 100]

// 내림차순
numbers.sort((a, b) => b - a);
console.log(numbers);  // [100, 40, 25, 10, 5]

검색 메서드

indexOf() / lastIndexOf()

1
2
3
4
5
let fruits = ["사과", "바나나", "오렌지", "바나나", "포도"];

console.log(fruits.indexOf("바나나"));      // 1 (첫 번째 위치)
console.log(fruits.lastIndexOf("바나나"));  // 3 (마지막 위치)
console.log(fruits.indexOf("딸기"));        // -1 (없음)

includes() - ES2016

1
2
3
4
let fruits = ["사과", "바나나", "오렌지"];

console.log(fruits.includes("바나나"));  // true
console.log(fruits.includes("딸기"));    // false

find() / findIndex() - ES6

1
2
3
4
5
6
7
8
9
10
11
12
13
let users = [
  { id: 1, name: "홍길동" },
  { id: 2, name: "김철수" },
  { id: 3, name: "이영희" }
];

// find: 조건에 맞는 첫 번째 요소
let user = users.find(user => user.id === 2);
console.log(user);  // { id: 2, name: "김철수" }

// findIndex: 조건에 맞는 첫 번째 요소의 인덱스
let index = users.findIndex(user => user.name === "이영희");
console.log(index);  // 2

배열 순회

for 문

1
2
3
4
5
let fruits = ["사과", "바나나", "오렌지"];

for (let i = 0; i < fruits.length; i++) {
  console.log(fruits[i]);
}

for…of (ES6)

1
2
3
4
5
let fruits = ["사과", "바나나", "오렌지"];

for (let fruit of fruits) {
  console.log(fruit);
}

forEach()

1
2
3
4
5
6
7
8
9
10
let fruits = ["사과", "바나나", "오렌지"];

fruits.forEach(function(fruit, index) {
  console.log(index, fruit);
});

// 화살표 함수
fruits.forEach((fruit, index) => {
  console.log(`${index}: ${fruit}`);
});

고차 함수 (Higher-Order Functions)

map() - 변환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let numbers = [1, 2, 3, 4, 5];

// 각 요소를 2배로
let doubled = numbers.map(num => num * 2);
console.log(doubled);  // [2, 4, 6, 8, 10]

// 객체 배열 변환
let users = [
  { name: "홍길동", age: 30 },
  { name: "김철수", age: 25 }
];

let names = users.map(user => user.name);
console.log(names);  // ["홍길동", "김철수"]

filter() - 필터링

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 짝수만
let evens = numbers.filter(num => num % 2 === 0);
console.log(evens);  // [2, 4, 6, 8, 10]

// 5보다 큰 수
let greaterThan5 = numbers.filter(num => num > 5);
console.log(greaterThan5);  // [6, 7, 8, 9, 10]

// 객체 필터링
let users = [
  { name: "홍길동", age: 30, active: true },
  { name: "김철수", age: 25, active: false },
  { name: "이영희", age: 35, active: true }
];

let activeUsers = users.filter(user => user.active);
console.log(activeUsers);
// [{ name: "홍길동", age: 30, active: true },
//  { name: "이영희", age: 35, active: true }]

reduce() - 집계

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let numbers = [1, 2, 3, 4, 5];

// 합계
let sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum);  // 15

// 곱셈
let product = numbers.reduce((acc, num) => acc * num, 1);
console.log(product);  // 120

// 최대값
let max = numbers.reduce((acc, num) => Math.max(acc, num));
console.log(max);  // 5

// 객체로 변환
let fruits = ["사과", "바나나", "오렌지"];
let fruitObj = fruits.reduce((acc, fruit, index) => {
  acc[index] = fruit;
  return acc;
}, {});
console.log(fruitObj);  // { 0: "사과", 1: "바나나", 2: "오렌지" }

메서드 체이닝

1
2
3
4
5
6
7
8
9
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 짝수만 필터링 → 2배로 → 합계
let result = numbers
  .filter(num => num % 2 === 0)
  .map(num => num * 2)
  .reduce((acc, num) => acc + num, 0);

console.log(result);  // 60 (2+4+6+8+10) * 2 = 60

실전 예제

1. 장바구니 합계

1
2
3
4
5
6
7
8
9
10
11
12
let cart = [
  { name: "노트북", price: 1500000, quantity: 1 },
  { name: "마우스", price: 30000, quantity: 2 },
  { name: "키보드", price: 80000, quantity: 1 }
];

let total = cart.reduce((sum, item) => {
  return sum + (item.price * item.quantity);
}, 0);

console.log(`총 금액: ${total.toLocaleString()}원`);
// "총 금액: 1,640,000원"

2. 데이터 그룹핑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let users = [
  { name: "홍길동", age: 30, city: "서울" },
  { name: "김철수", age: 25, city: "부산" },
  { name: "이영희", age: 35, city: "서울" },
  { name: "박민수", age: 28, city: "대전" }
];

let byCity = users.reduce((acc, user) => {
  if (!acc[user.city]) {
    acc[user.city] = [];
  }
  acc[user.city].push(user);
  return acc;
}, {});

console.log(byCity);
// {
//   서울: [{ name: "홍길동", ... }, { name: "이영희", ... }],
//   부산: [{ name: "김철수", ... }],
//   대전: [{ name: "박민수", ... }]
// }

3. 중복 제거

1
2
3
4
5
6
7
8
9
let numbers = [1, 2, 3, 2, 4, 3, 5, 1];

// Set 사용 (ES6)
let unique1 = [...new Set(numbers)];
console.log(unique1);  // [1, 2, 3, 4, 5]

// filter 사용
let unique2 = numbers.filter((num, index) => numbers.indexOf(num) === index);
console.log(unique2);  // [1, 2, 3, 4, 5]

4. 배열 평탄화 (Flatten)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let nested = [1, [2, 3], [4, [5, 6]], 7];

// flat() - ES2019
let flat1 = nested.flat(2);
console.log(flat1);  // [1, 2, 3, 4, 5, 6, 7]

// reduce 사용
function flatten(arr) {
  return arr.reduce((acc, val) => {
    return acc.concat(Array.isArray(val) ? flatten(val) : val);
  }, []);
}

let flat2 = flatten(nested);
console.log(flat2);  // [1, 2, 3, 4, 5, 6, 7]

마치며

JavaScript 배열은 데이터를 효율적으로 관리하는 핵심 자료구조입니다:

  1. 배열 생성: 리터럴 [] 사용 (권장)
  2. 인덱스: 0부터 시작하는 위치 번호
  3. 배열 메서드: push, pop, slice, splice 등
  4. 고차 함수: map, filter, reduce로 함수형 프로그래밍
  5. 배열 순회: for, forEach, for…of

배열 메서드를 능숙하게 사용하고, map/filter/reduce 같은 고차 함수를 활용하여 선언적이고 읽기 쉬운 코드를 작성하세요.

참고 자료

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.