JavaScript 배열 메서드: map, filter, reduce 완전 정복! 🚀
안녕, 친구들! 오늘은 JavaScript의 꿀잼 배열 메서드 삼총사인 map, filter, reduce에 대해 깊~게 파헤쳐볼 거야. 이 메서드들은 마치 재능넷에서 다양한 재능을 찾아 거래하듯이, 배열 데이터를 자유자재로 다룰 수 있게 해주는 강력한 도구들이지. 자, 그럼 우리 함께 이 신나는 JavaScript 여행을 떠나볼까? 😎
🎭 재능넷 TMI: 우리가 배울 이 메서드들은 마치 재능넷에서 다양한 재능을 찾고, 필터링하고, 조합하는 과정과 비슷해. 코딩의 세계에서도 이런 '재능'이 필요하다니, 재밌지 않아?
1. map() 메서드: 배열의 변신 마술사 🧙♂️
먼저 map() 메서드부터 알아볼게. 이 녀석은 마치 마법사처럼 배열의 각 요소를 새로운 모습으로 변신시켜주는 능력을 가졌어.
🎭 map()의 기본 사용법
const 원본배열 = [1, 2, 3, 4, 5];
const 변신배열 = 원본배열.map((요소) => 요소 * 2);
console.log(변신배열); // [2, 4, 6, 8, 10]
와우! 모든 숫자가 2배로 늘어났어. 마치 재능넷에서 자신의 재능을 업그레이드하는 것처럼 말이야.
🎨 map()으로 객체 배열 다루기
map()은 단순한 숫자 배열뿐만 아니라 복잡한 객체 배열도 자유자재로 다룰 수 있어.
const 사용자들 = [
{ 이름: '김코딩', 나이: 25 },
{ 이름: '박해커', 나이: 30 },
{ 이름: '이개발', 나이: 28 }
];
const 인사말 = 사용자들.map((사용자) => `안녕하세요, ${사용자.이름}님! ${사용자.나이}살이시네요.`);
console.log(인사말);
// ["안녕하세요, 김코딩님! 25살이시네요.", "안녕하세요, 박해커님! 30살이시네요.", "안녕하세요, 이개발님! 28살이시네요."]
이렇게 map()을 사용하면 복잡한 데이터도 쉽게 변형할 수 있어. 마치 재능넷에서 다양한 재능을 가진 사람들의 프로필을 한눈에 볼 수 있게 정리하는 것과 비슷하지?
🚀 map()의 고급 활용
map()은 단순히 배열의 요소를 변형하는 것 외에도 다양한 방식으로 활용할 수 있어.
const 숫자들 = [1, 4, 9, 16, 25];
const 제곱근과인덱스 = 숫자들.map((숫자, 인덱스) => ({
원본: 숫자,
제곱근: Math.sqrt(숫자),
인덱스: 인덱스
}));
console.log(제곱근과인덱스);
// [
// { 원본: 1, 제곱근: 1, 인덱스: 0 },
// { 원본: 4, 제곱근: 2, 인덱스: 1 },
// { 원본: 9, 제곱근: 3, 인덱스: 2 },
// { 원본: 16, 제곱근: 4, 인덱스: 3 },
// { 원본: 25, 제곱근: 5, 인덱스: 4 }
// ]
이렇게 map()을 사용하면 원본 데이터를 유지하면서도 새로운 정보를 추가할 수 있어. 마치 재능넷에서 사용자의 기본 정보에 추가적인 스킬 정보를 덧붙이는 것과 비슷하지?
💡 꿀팁: map() 메서드는 원본 배열을 변경하지 않고 새로운 배열을 반환해. 이는 데이터의 안전성을 지키면서도 유연하게 작업할 수 있게 해주는 큰 장점이야!
🎭 map()의 실전 활용 예제
자, 이제 map()을 실제 상황에서 어떻게 활용할 수 있는지 더 자세히 알아볼까?
const 상품목록 = [
{ 이름: '노트북', 가격: 1000000, 재고: 5 },
{ 이름: '스마트폰', 가격: 800000, 재고: 10 },
{ 이름: '태블릿', 가격: 500000, 재고: 7 }
];
const 할인상품 = 상품목록.map(상품 => ({
...상품,
할인가격: 상품.가격 * 0.9,
총액: 상품.가격 * 상품.재고
}));
console.log(할인상품);
// [
// { 이름: '노트북', 가격: 1000000, 재고: 5, 할인가격: 900000, 총액: 5000000 },
// { 이름: '스마트폰', 가격: 800000, 재고: 10, 할인가격: 720000, 총액: 8000000 },
// { 이름: '태블릿', 가격: 500000, 재고: 7, 할인가격: 450000, 총액: 3500000 }
// ]
이 예제에서는 원래 상품 정보에 10% 할인된 가격과 총 재고 가치를 추가했어. 이런 식으로 map()을 사용하면 복잡한 데이터 처리도 간단하게 할 수 있지.
🌈 map()의 창의적 활용
map()은 단순히 데이터 변환을 넘어서 창의적인 방식으로도 활용할 수 있어. 예를 들어, ASCII 아트를 만드는 데 사용할 수도 있지!
const 숫자배열 = [1, 2, 3, 4, 5];
const ASCII아트 = 숫자배열.map(num => '*'.repeat(num)).join('\n');
console.log(ASCII아트);
// *
// **
// ***
// ****
// *****
이렇게 map()을 사용하면 데이터를 시각적으로 표현하는 것도 가능해. 마치 재능넷에서 다양한 재능을 시각화하는 것처럼 말이야!
이 그림은 map() 메서드가 어떻게 작동하는지를 보여주고 있어. 원본 배열의 각 요소가 어떻게 새로운 값으로 변환되는지 한눈에 볼 수 있지? 이처럼 map()은 배열의 각 요소를 순회하면서 지정된 함수를 적용해 새로운 배열을 만들어내는 거야.
🤔 map()을 사용할 때 주의할 점
map()은 정말 유용한 메서드지만, 사용할 때 주의해야 할 점도 있어.
- map()은 항상 원본 배열과 같은 길이의 새 배열을 반환해. 만약 일부 요소만 변환하고 싶다면 filter()와 함께 사용하는 것이 좋아.
- map() 내부에서 원본 배열을 수정하지 않도록 주의해야 해. 예상치 못한 부작용이 발생할 수 있거든.
- 큰 배열에 대해 복잡한 연산을 수행하는 경우, 성능에 영향을 줄 수 있어. 이런 경우에는 for 루프를 사용하는 것이 더 효율적일 수 있지.
이런 점들을 주의하면서 map()을 사용하면, 정말 강력하고 유연한 도구로 활용할 수 있어!
2. filter() 메서드: 배열의 엄격한 문지기 🚧
이제 filter() 메서드에 대해 알아볼 차례야. 이 메서드는 마치 엄격한 문지기처럼 조건에 맞는 요소만 통과시켜 새로운 배열을 만들어내지.
🎭 filter()의 기본 사용법
const 숫자들 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const 짝수들 = 숫자들.filter((숫자) => 숫자 % 2 === 0);
console.log(짝수들); // [2, 4, 6, 8, 10]
짜잔! 짝수만 골라냈어. 마치 재능넷에서 특정 조건에 맞는 재능을 가진 사람들만 필터링하는 것과 비슷하지?
🕵️♂️ filter()로 복잡한 조건 다루기
filter()는 단순한 조건뿐만 아니라 복잡한 조건도 쉽게 다룰 수 있어.
const 사용자들 = [
{ 이름: '김코딩', 나이: 25, 직업: '개발자' },
{ 이름: '박해커', 나이: 30, 직업: '디자이너' },
{ 이름: '이개발', 나이: 28, 직업: '개발자' },
{ 이름: '최기획', 나이: 32, 직업: '기획자' }
];
const 젊은개발자들 = 사용자들.filter((사용자) => 사용자.나이 < 30 && 사용자.직업 === '개발자');
console.log(젊은개발자들);
// [{ 이름: '김코딩', 나이: 25, 직업: '개발자' }]
이렇게 여러 조건을 조합해서 원하는 데이터만 정확하게 골라낼 수 있어. 재능넷에서 특정 나이대의 특정 직업을 가진 사람들만 찾는 것과 비슷하지?
🚀 filter()의 고급 활용
filter()는 단순히 요소를 걸러내는 것 외에도 다양한 방식으로 활용할 수 있어.
const 문자열배열 = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
const 긴단어들 = 문자열배열.filter((단어) => 단어.length > 5);
console.log(긴단어들); // ['banana', 'elderberry']
const 중복제거 = (배열) => 배열.filter((요소, 인덱스) => 배열.indexOf(요소) === 인덱스);
console.log(중복제거([1, 2, 2, 3, 4, 4, 5])); // [1, 2, 3, 4, 5]
이렇게 filter()를 사용하면 문자열의 길이를 기준으로 필터링하거나, 심지어 배열에서 중복된 요소를 제거하는 것도 가능해. 마치 재능넷에서 특정 기준을 만족하는 재능만 골라내거나, 중복된 재능 등록을 방지하는 것과 비슷하지?
💡 꿀팁: filter() 메서드도 map()과 마찬가지로 원본 배열을 변경하지 않아. 이는 원본 데이터의 무결성을 유지하면서 필요한 데이터만 추출할 수 있게 해주는 큰 장점이야!
🎭 filter()의 실전 활용 예제
자, 이제 filter()를 실제 상황에서 어떻게 활용할 수 있는지 더 자세히 알아볼까?
const 상품목록 = [
{ 이름: '노트북', 가격: 1000000, 재고: 5 },
{ 이름: '스마트폰', 가격: 800000, 재고: 0 },
{ 이름: '태블릿', 가격: 500000, 재고: 2 },
{ 이름: '이어폰', 가격: 200000, 재고: 10 }
];
const 구매가능상품 = 상품목록.filter(상품 => 상품.재고 > 0 && 상품.가격 <= 800000);
console.log(구매가능상품);
// [
// { 이름: '태블릿', 가격: 500000, 재고: 2 },
// { 이름: '이어폰', 가격: 200000, 재고: 10 }
// ]
이 예제에서는 재고가 있고 가격이 80만원 이하인 상품만 필터링했어. 이런 식으로 filter()를 사용하면 복잡한 조건에 맞는 데이터를 쉽게 추출할 수 있지.
🌈 filter()의 창의적 활용
filter()는 단순히 데이터 필터링을 넘어서 창의적인 방식으로도 활용할 수 있어. 예를 들어, 소수(Prime Number)를 찾는 데 사용할 수도 있지!
const 소수찾기 = (최대값) => {
return Array.from({ length: 최대값 - 1 }, (_, i) => i + 2).filter((num) => {
for (let i = 2; i <= Math.sqrt(num); i++) {
if (num % i === 0) return false;
}
return true;
});
};
console.log(소수찾기(20)); // [2, 3, 5, 7, 11, 13, 17, 19]
이렇게 filter()를 사용하면 복잡한 수학적 개념도 간단하게 구현할 수 있어. 마치 재능넷에서 특별한 재능을 가진 사람들을 찾아내는 것처럼 말이야!
이 그림은 filter() 메서드가 어떻게 작동하는지를 보여주고 있어. 원본 배열에서 조건(여기서는 짝수)에 맞는 요소만 새로운 배열로 필터링되는 과정을 볼 수 있지? 이처럼 filter()는 배열의 각 요소를 순회하면서 지정된 조건을 만족하는 요소만을 새로운 배열에 포함시키는 거야.
🤔 filter()를 사용할 때 주의할 점
filter()는 정말 유용한 메서드지만, 사용할 때 주의해야 할 점도 있어.
- filter()는 항상 새로운 배열을 반환해. 따라서 메모리 사용량에 주의해야 해, 특히 큰 배열을 다룰 때는 더욱 그래.
- filter() 내부에서 원본 배열을 수정하지 않도록 주의해야 해. 예상치 못한 결과가 나올 수 있거든.
- 복잡한 객체를 필터링할 때는 깊은 복사(deep copy)를 고려해야 할 수도 있어. 그렇지 않으면 원본 객체가 변경될 수 있어.
- filter()는 'truthy' 값을 반환하는 모든 요소를 포함시켜. 이 점을 잘 이해하고 사용해야 해.
이런 점들을 주의하면서 filter()를 사용하면, 데이터를 정확하고 효율적으로 필터링할 수 있어!
3. reduce() 메서드: 배열의 만능 요리사 👨🍳
마지막으로 reduce() 메서드를 알아볼 차례야. 이 메서드는 마치 만능 요리사처럼 배열의 요소들을 다양한 방식으로 조합해 하나의 결과값을 만들어내지.
🎭 reduce()의 기본 사용법
const 숫자들 = [1, 2, 3, 4, 5];
const 합계 = 숫자들.reduce((누적값, 현재값) => 누적값 + 현재값, 0);
console.log(합계); // 15
와! 모든 숫자를 더해서 하나의 값으로 만들었어. 마치 재능넷에서 여러 사람의 재능을 모아 하나의 프로젝트를 완성하는 것과 비슷하지?
🧮 reduce()로 복잡한 연산 수행하기
reduce()는 단순한 덧셈 외에도 다양한 복잡한 연산을 수행할 수 있어.
const 투표결과 = ['김후보', '이후보', '박후보', '김후보', '이후보', '김후보'];
const 투표집계 = 투표결과.reduce((집계, 후보) => {
집계[후보] = (집계[후보] || 0) + 1;
return 집계;
}, {});
console.log(투표집계);
// { '김후보': 3, '이후보': 2, '박후보': 1 }
이렇게 reduce()를 사용하면 복잡한 데이터 구조도 쉽게 만들 수 있어. 재능넷에서 다양한 재능의 인기도를 집계하는 것과 비슷하지?
🚀 reduce()의 고급 활용
reduce()는 정말 다재다능해서 map()이나 filter()의 기능도 대신할 수 있어!
const 숫자배열 = [1, 2, 3, 4, 5];
// map 기능 구현
const 제곱배열 = 숫자배열.reduce((결과, 숫자) => {
결과.push(숫자 * 숫자);
return 결과;
}, []);
console.log(제곱배열); // [1, 4, 9, 16, 25]
// filter 기능 구현
const 짝수배열 = 숫자배열.reduce((결과, 숫자) => {
if (숫자 % 2 === 0) 결과.push(숫자);
return 결과;
}, []);
console.log(짝수배열); // [2, 4]
이렇게 reduce()를 사용하면 다른 배열 메서드들의 기능도 구현할 수 있어. 마치 재능넷에서 한 사람이 여러 가지 재능을 가지고 다양한 역할을 수행하는 것과 비슷하지?
💡 꿀팁: reduce()는 초기값을 설정할 수 있어. 초기값을 제공하면 배열이 비어있을 때도 안전하게 작동하고, 원하는 데이터 타입으로 결과를 만들 수 있어!
🎭 reduce()의 실전 활용 예제
자, 이제 reduce()를 실제 상황에서 어떻게 활용할 수 있는지 더 자세히 알아볼까?
const 주문목록 = [
{ 상품: '노트북', 가격: 1000000, 수량: 2 },
{ 상품: '마우스', 가격: 20000, 수량: 5 },
{ 상품: '키보드', 가격: 50000, 수량: 3 }
];
const 주문분석 = 주문목록.reduce((결과, 주문) => {
결과.총액 += 주문.가격 * 주문.수량;
결과.총수량 += 주문.수량;
if (주문.가격 * 주문.수량 > 결과.최고가주문.금액) {
결과.최고가주문 = { 상품: 주문.상품, 금액: 주문.가격 * 주문.수량 };
}
return 결과;
}, { 총액: 0, 총수량: 0, 최고가주문: { 상품: '', 금액: 0 } });
console.log(주문분석);
// {
// 총액: 2150000,
// 총수량: 10,
// 최고가주문: { 상품: '노트북', 금액: 2000000 }
// }
이 예제에서는 주문 목록을 분석해서 총액, 총 수량, 그리고 가장 비싼 주문을 한 번에 계산했어. 이런 식으로 reduce()를 사용하면 복잡한 데이터 분석도 한 번의 순회로 효율적으로 수행할 수 있지.
🌈 reduce()의 창의적 활용
reduce()는 정말 다재다능해서 아주 창의적인 방식으로도 활용할 수 있어. 예를 들어, 배열을 사용해 간단한 상태 관리 시스템을 만들 수도 있지!
const 상태변경 = [
{ type: 'INCREMENT', payload: 5 },
{ type: 'DECREMENT', payload: 3 },
{ type: 'MULTIPLY', payload: 2 },
{ type: 'DIVIDE', payload: 4 }
];
const 상태관리 = (초기값, 액션들) => {
return 액션들.reduce((상태, 액션) => {
switch (액션.type) {
case 'INCREMENT':
return 상태 + 액션.payload;
case 'DECREMENT':
return 상태 - 액션.payload;
case 'MULTIPLY':
return 상태 * 액션.payload;
case 'DIVIDE':
return 상태 / 액션.payload;
default:
return 상태;
}
}, 초기값);
};
console.log(상태관리(10, 상태변경)); // 3
이렇게 reduce()를 사용하면 복잡한 상태 관리 로직도 간단하게 구현할 수 있어. 마치 재능넷에서 여러 사람의 재능을 조합해 하나의 복잡한 프로젝트를 완성하는 것과 비슷하지?
이 그림은 reduce() 메서드가 어떻게 작동하는지를 보여주고 있어. 배열의 모든 요소가 하나씩 누적되어 최종적으로 하나의 결과값(여기서는 합계)으로 줄어드는 과정을 볼 수 있지? 이처럼 reduce()는 배열의 각 요소를 순회하면서 누적된 결과값을 계산해나가는 거야.
🤔 reduce()를 사용할 때 주의할 점
reduce()는 정말 강력한 메서드지만, 사용할 때 주의해야 할 점도 있어.
- 초기값을 제공하는 것이 안전해. 배열이 비어있을 때 오류를 방지할 수 있거든.
- 복잡한 로직을 reduce() 안에 넣으면 코드 가독성이 떨어질 수 있어. 필요하다면 별도의 함수로 분리하는 것이 좋아.
- 큰 배열에 대해 복잡한 연산을 수행할 때는 성능에 주의해야 해. 때로는 일반 for 루프가 더 효율적일 수 있어.
- reduce()는 비동기 작업에는 적합하지 않아. 비동기 작업을 다룰 때는 다른 방법을 고려해봐야 해.