isNaN, Number.isNaN
✅ isNaN(value)
- 매개변수를 Number(value)로 변환 후 NaN인지 검사함.
- 숫자로 변환할 수 없는 문자열을 넣으면 Number(value)가 NaN이 되므로 true를 반환.
- 예제
isNaN('hello'); // true (Number('hello') → NaN) isNaN(undefined); // true (Number(undefined) → NaN) isNaN('123'); // false (Number('123') → 123) isNaN({}); // true (Number({}) → NaN) isNaN(' '); // false (Number(' ') → 0)
- 타입스크립트에서의 문제점
- isNaN(value: number): boolean으로 타입이 지정되어 있기 때문에, string을 넣으면 타입 오류 발생.
- 하지만 JavaScript에서 isNaN()은 문자열도 암묵적으로 Number() 변환을 시도하기 때문에 타입 안정성이 떨어짐.
✅ Number.isNaN(value)
- 매개변수를 Number(value)로 변환하지 않고 그대로 NaN인지 검사함.
- 즉, 오직 NaN 값만 true를 반환.
- 예제
Number.isNaN('hello'); // false ('hello'는 NaN이 아님) Number.isNaN(undefined); // false (undefined는 NaN이 아님) Number.isNaN(NaN); // true (NaN은 NaN이 맞음) Number.isNaN(123); // false (숫자는 NaN이 아님) Number.isNaN('123'); // false ('123'은 NaN이 아님)
- 타입스크립트에서의 장점:
- Number.isNaN(value: unknown): boolean → unknown을 받기 때문에 어떤 타입이든 허용됨.
- 값이 NaN인지 정확히 판별 가능.
✨ 결론
- isNaN(value): 값을 숫자로 변환 후 NaN인지 검사 (의도하지 않은 변환 문제 발생 가능).
- Number.isNaN(value): 그 값 자체가 NaN인지 직접 검사 (더 엄격하고 타입 안정적).
따라서, 실무에서는 Number.isNaN(value)를 쓰는 것이 더 안전하다!
split(), splice(), slice() 비교
메서드 | 사용 대상 | 역할 | 원본 변경 여부 |
split() | 문자열 | 구분자로 나누어 배열로 변환 | ❌ 변경 안 함 |
splice() | 배열 | 요소 추가, 삭제, 교체 | ✅ 변경됨 |
slice() | 배열 & 문자열 | 일부 요소/문자만 가져옴 | ❌ 변경 안 함 |
✅ split() (문자열을 배열로 변환)
문자열에서 특정 구분자로 나누고 싶을 때 사용
const str = "apple,banana,grape"; const result = str.split(","); // 쉼표(,)를 기준으로 분리 console.log(result); // ["apple", "banana", "grape"] console.log(str); // "apple,banana,grape" (원본 변경 없음)
- 구분자를 기준으로 문자열을 나눔
- 결과는 배열(Array)
- 원본 문자열 변경 없음(immutable)
✅ splice() (배열에서 요소 추가/삭제/교체)
배열의 요소를 제거하거나 새로운 요소를 추가할 때 사용
const arr = ["apple", "banana", "grape"]; arr.splice(1, 1, "orange"); // 1번 인덱스부터 1개 삭제 후 "orange" 추가 console.log(arr); // ["apple", "orange", "grape"]
- 첫 번째 인자: 시작 인덱스
- 두 번째 인자: 삭제할 요소 개수
- 세 번째 이후 인자: 추가할 요소
- 원본 배열이 변경됨(mutable)
✅ slice() (배열/문자열 일부 추출)
배열이나 문자열에서 일부만 복사해서 새로운 배열/문자열을 반환
const fruits = ["apple", "banana", "grape", "orange"]; const slicedFruits = fruits.slice(1, 3); // 1번부터 3번 이전까지(1,2) 복사 console.log(slicedFruits); // ["banana", "grape"] console.log(fruits); // ["apple", "banana", "grape", "orange"] (원본 변경 없음)
const str = "Hello World"; const slicedStr = str.slice(0, 5); // 0번부터 5번 이전까지("Hello") console.log(slicedStr); // "Hello" console.log(str); // "Hello World" (원본 변경 없음)
- 첫 번째 인자: 시작 인덱스
- 두 번째 인자(선택적): 종료 인덱스(포함되지 않음)
- 원본 데이터 변경 없음(immutable)
💡 어떤 상황에서 사용하면 될까?
- 문자열을 나누고 싶다면? →
split()
- 배열에서 요소를 삭제하거나 추가해야 한다면? →
splice()
- 배열/문자열의 일부만 복사하고 싶다면? →
slice()
✅ 가장 큰 차이점
split()
: 문자열 → 배열 변환splice()
: 배열 조작(삭제/추가/교체, 원본 변경)slice()
: 일부 요소/문자만 가져오기(원본 유지)
reduce()
와 map()
에서 return을 사용하는 이유
reduce()
와map()
은 배열을 변형하거나 새로운 값을 생성하는 메서드이므로, 각 콜백 함수에서 return을 사용하여 원하는 값을 반환해야 한다.- {}를 사용하기 위해서는 return이 반드시 필요하다.
reduce()
의 다양한 활용 예제
reduce()
는 배열을 하나의 값으로 축약할 때 사용된다.
✔️ 누적 연산, 변형, 그룹화 등 다양한 용도로 활용 가능하다
✅ 1. 배열 숫자 합 구하기 (기본적인 reduce() 활용)
const numbers = [1, 2, 3, 4, 5]; const sum = numbers.reduce((acc, num) => acc + num, 0); console.log(sum); // 15
✔️ acc(누적값) 초기값을 0으로 설정 → 배열의 모든 값을 더함.
✅ 2. 최대값 찾기
const numbers = [3, 7, 2, 8, 5]; const max = numbers.reduce((acc, num) => (num > acc ? num : acc), numbers[0]); console.log(max); // 8
✔️ num > acc이면 새로운 최대값을 acc로 업데이트.
✅ 3. 객체 배열에서 특정 값 합산하기
const orders = [ { item: "Apple", price: 3, quantity: 2 }, { item: "Banana", price: 1, quantity: 5 }, { item: "Orange", price: 2, quantity: 4 } ]; const totalPrice = orders.reduce((acc, order) => acc + order.price * order.quantity, 0); console.log(totalPrice); // 19
✔️ 각 아이템의 price * quantity를 계산 후 전체 합산.
✅ 4. 배열의 중복 요소 개수 세기 (빈도수 계산)
const fruits = ["apple", "banana", "apple", "orange", "banana", "banana"]; const count = fruits.reduce((acc, fruit) => { acc[fruit] = (acc[fruit] || 0) + 1; return acc; }, {}); console.log(count); // { apple: 2, banana: 3, orange: 1 }
✔️ acc를 객체로 활용하여 각 과일의 등장 횟수를 카운트.
✅ 5. 중첩 배열(flatten) 펼치기
const nestedArray = [[1, 2], [3, 4], [5, 6]]; const flattened = nestedArray.reduce((acc, arr) => acc.concat(arr), []); console.log(flattened); // [1, 2, 3, 4, 5, 6]
✔️ concat()
을 이용해 중첩 배열을 단일 배열로 변환.
✅ 6. 문자열 문자 개수 카운트
const sentence = "hello world"; const charCount = sentence.split("").reduce((acc, char) => { if (char !== " ") acc[char] = (acc[char] || 0) + 1; return acc; }, {}); console.log(charCount); // { h: 1, e: 1, l: 3, o: 2, w: 1, r: 1, d: 1 }
✔️ 문자열을 split("")
으로 배열로 변환 후, 각 문자의 개수를 카운트.
✅ 7. 배열의 특정 조건 필터링 (map + filter 역할 대체)
const numbers = [1, 2, 3, 4, 5, 6]; const evenNumbers = numbers.reduce((acc, num) => { if (num % 2 === 0) acc.push(num); return acc; }, []); console.log(evenNumbers); // [2, 4, 6]
✔️ reduce()
만으로 filter()
와 같은 기능 구현 가능.
🎯 정리
용도 | 설명 |
누적 연산 | 합, 곱, 최대값, 최소값 찾기 |
배열 변환 | map(), filter() 대체 |
데이터 그룹화 | 중복 요소 개수 카운트 |
배열 평탄화 | 중첩 배열을 1차원 배열로 변환 |
결론
- reduce()는 배열을 하나의 값으로 축약하는 강력한 도구
- map(), filter(), forEach()로 해결할 수 있는 것도 있지만, 특정 상황에서는 reduce()가 더 효율적이고 가독성이 좋다
map()
vs reduce()
✅ map() → 각 요소를 변환하여 새로운 배열 반환
🧐 return을 반드시 써야 하는 이유?
→ map()은 배열의 각 요소를 변환한 후 새로운 배열을 반환하기 때문!
const numbers = [1, 2, 3, 4]; const squared = numbers.map(num => num * num); // 각 요소를 제곱 console.log(squared); // [1, 4, 9, 16]
📌 특징
- 기존 배열을 변경하지 않고, 변형된 새 배열을 반환.
- 반환값이 없으면(return 생략) undefined가 들어간 배열이 생성됨.
const result = numbers.map(num => { num * num }); // 중괄호
{}
사용 시 return 필요 console.log(result); // [undefined, undefined, undefined, undefined] - ❌ return 생략 시:
💡 즉, map()을 사용할 때는 반드시 return을 통해 변환된 값을 반환해야 함.
✅ reduce() → 배열을 하나의 값으로 축약
🧐 return을 반드시 써야 하는 이유?
→ reduce()는 이전 콜백 결과를 누적하여 최종적으로 단일 값을 반환하기 때문
const numbers = [1, 2, 3, 4]; const sum = numbers.reduce((acc, num) => acc + num, 0); console.log(sum); // 10
📌 특징
- acc(누적값)을 계속 업데이트하면서 최종 결과를 만듦.
- 반환값이 없으면(return 생략) undefined가 누적됨.
const result = numbers.reduce((acc, num) => { acc + num }, 0); console.log(result); // undefined (acc에 아무것도 누적되지 않음)
- ❌ return 생략 시:
💡 즉, reduce()에서는 return을 사용해 반드시 누적할 값을 반환해야 함.
🎯 map() vs reduce() 차이점 정리
메서드 | 목적 | return 필요 여부 | 반환값 |
map() | 배열 변환 | ✅ 필수 (새 배열 생성) | 변형된 새로운 배열 |
reduce() | 배열을 하나의 값으로 축약 | ✅ 필수 (누적값 업데이트) | 최종 단일 값 |
🚀 결론
- map()은 변형된 값을 새 배열로 반환해야 하므로 return이 필요함
- reduce()는 누적값을 업데이트하여 최종 결과를 반환해야 하므로 return이 필요함
- 💡 return을 생략하면 undefined가 들어가거나 연산이 제대로 수행되지 않음