심벌 (Symbol)
1. 심벌값의 생성
- 심벌은 ES6에서 도입된 원시 타입 중 하나임
- Symbol() 함수 호출로 생성함
- 생성된 심벌값은 유일무이함
- new 연산자 사용 불가
- 심벌값은 문자열로 자동 변환되지 않음
const sym1 = Symbol('desc');
const sym2 = Symbol('desc');
console.log(sym1 === sym2); // false
2. 심벌과 상수
- 중복되지 않는 상수 값 생성 시 유용함
- 주로 enum 대체 용도로 사용됨
const DIRECTION = {
UP: Symbol('up'),
DOWN: Symbol('down')
};
3. 심벌과 프로퍼티 키
- 객체 프로퍼티 키로 심벌 사용 가능함
- 문자열 키와 달리 충돌 위험 없음
const key = Symbol('key');
const obj = {
[key]: 'value'
};
console.log(obj[key]); // value
4. 심벌과 프로퍼티 은닉
- 심벌 키 프로퍼티는 기본적인 순회에서 노출되지 않음
- for...in, Object.keys(), JSON.stringify() 등에서 제외됨
- 은닉 프로퍼티처럼 사용 가능함
const secret = Symbol('secret');
const user = {
name: 'Alice',
[secret]: 'hidden'
};
console.log(Object.keys(user)); // ['name']
5. 심벌과 표준 빌트인 객체 확장
- 빌트인 객체의 기존 메서드 충돌 없이 새로운 메서드 추가 가능함
const custom = Symbol('custom');
Array.prototype[custom] = function() {
return 'custom method';
};
const arr = [];
console.log(arr[custom]()); // custom method
6. Well-known Symbol
- 자바스크립트 엔진이 미리 정의한 심벌 값
- 객체 동작을 커스터마이징하는 데 사용함
심벌 설명
Symbol.iterator | for...of 루프 동작 정의 |
Symbol.asyncIterator | 비동기 반복자 정의 |
Symbol.toStringTag | 객체의 기본 toString 태그 변경 |
Symbol.hasInstance | instanceof 연산자 동작 정의 |
Symbol.isConcatSpreadable | 배열 concat 시 전개 여부 결정 |
Symbol.species | 파생 객체 생성자 결정 |
Symbol.match | 문자열 매칭 동작 정의 |
Symbol.replace | 문자열 치환 동작 정의 |
Symbol.search | 문자열 검색 동작 정의 |
Symbol.split | 문자열 분할 동작 정의 |
class Custom {
get [Symbol.toStringTag]() {
return 'CustomObject';
}
}
const c = new Custom();
console.log(Object.prototype.toString.call(c)); // [object CustomObject]
이터러블(Iterable)
1. 이터레이션 프로토콜
- 이터러블 프로토콜과 이터레이터 프로토콜로 구성됨
- 이터러블 프로토콜: 객체가 Symbol.iterator 메서드를 가져야 함
- 이터레이터 프로토콜: next() 메서드를 호출할 때 { value, done } 형태 객체 반환해야 함
- done이 true이면 반복 종료 의미함
- 자바스크립트의 순회 가능한 객체는 이 두 프로토콜을 모두 준수함
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
2. 빌트인 이터러블
- Array, String, Map, Set, TypedArray, arguments, DOM 컬렉션(NodeList 등) 등이 빌트인 이터러블 객체임
- 이들은 모두 for...of문, 스프레드 문법, 배열 디스트럭처링 등에 사용 가능함
const str = 'hello';
for (const char of str) {
console.log(char);
}
3. for ...of 문
- 이터러블 객체 순회 전용 반복문임
- 내부적으로 이터레이터 프로토콜 사용함
- for...in은 열거 가능한 속성 순회, for...of는 값 자체 순회
const arr = [10, 20, 30];
for (const val of arr) {
console.log(val);
}
4. 이터러블과 유사 배열 객체
- 유사 배열 객체(Array-like Object)는 length 프로퍼티를 가진 객체임
- 예: arguments, NodeList 등
- 배열 메서드 사용 불가, 이터러블이 아닐 수도 있음
- 스프레드 문법이나 Array.from()으로 배열 변환 가능함
function test() {
console.log(arguments); // 유사 배열 객체
const arr = Array.from(arguments);
console.log(arr.map(x => x * 2));
}
test(1, 2, 3);
5. 이터레이션 프로토콜의 필요성
- 다양한 데이터 소스를 동일한 방법으로 순회 가능하게 함
- 일관된 순회 인터페이스 제공으로 코드 재사용성 향상
- ES6의 스프레드 문법, for...of, 디스트럭처링 할당, Promise.all 등에서 활용됨
const set = new Set([1, 2, 3]);
console.log([...set]); // [1, 2, 3]
6. 사용자 정의 이터러블
- 직접 Symbol.iterator 메서드 구현하여 이터러블 객체 생성 가능함
const customIterable = {
values: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
const values = this.values;
return {
next() {
if (index < values.length) {
return { value: values[index++], done: false };
} else {
return { done: true };
}
}
};
}
};
for (const val of customIterable) {
console.log(val);
}
- 위 예시에서 customIterable 객체는 직접 이터레이터를 구현했기 때문에 for...of문 사용 가능함
스프레드 문법(Spread Syntax)
1. 함수 호출문의 인수 목록에서 사용하는 경우
- 스프레드 문법은 ... 기호 사용함
- 배열이나 이터러블 요소를 개별 인수로 확장하는 역할 함
- Function.prototype.apply()를 대체하는 간결한 문법 제공함
- 함수 호출 시 가독성 향상 및 코드 간결화 가능함
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6
- Math.max() 같이 여러 인수를 받는 함수에도 사용 가능함
const values = [10, 20, 30];
console.log(Math.max(...values)); // 30
2. 배열 리터럴 내부에서 사용하는 경우
- 배열 결합, 복사 시 활용 가능함
- concat() 메서드 없이도 간결하게 배열 병합 가능함
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4]
- 배열 복사 시 얕은 복사 수행함
const original = [1, 2, 3];
const copy = [...original];
console.log(copy); // [1, 2, 3]
console.log(original === copy); // false
- 문자열도 배열처럼 전개 가능함
const str = 'hello';
console.log([...str]); // ['h', 'e', 'l', 'l', 'o']
3. 객체 리터럴 내부에서 사용하는 경우
- ES2018에서 도입된 기능임
- 기존 객체를 전개하여 새로운 객체 생성 가능함
- 객체 병합 시 Object.assign()을 대체함
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 3, c: 4 }
- 얕은 복사 수행, 중첩 객체는 참조 복사됨
const nested = { x: { y: 1 } };
const copyNested = { ...nested };
copyNested.x.y = 2;
console.log(nested.x.y); // 2 (얕은 복사로 인한 영향)
- 새로운 프로퍼티 추가하면서 복사 가능함
const user = { name: 'Alice', age: 20 };
const updated = { ...user, age: 21, city: 'Seoul' };
console.log(updated); // { name: 'Alice', age: 21, city: 'Seoul' }
디스트럭처링 할당(Destructuring Assignment)
1. 배열 디스트럭처링 할당
- 배열의 요소를 개별 변수로 쉽게 할당하는 문법임
- 인덱스 순서대로 변수에 값이 할당됨
- 코드 간결화와 가독성 향상에 유용함
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a, b, c); // 1 2 3
기본값 할당
- 배열 요소가 undefined인 경우 기본값 할당 가능함
const [x, y, z = 5] = [10, 20];
console.log(x, y, z); // 10 20 5
필요 없는 요소 무시
- 쉼표로 요소를 건너뛸 수 있음
const [first, , third] = [1, 2, 3];
console.log(first, third); // 1 3
나머지 요소 할당(Rest)
- 나머지 요소를 배열로 모아 할당 가능함
const [head, ...rest] = [1, 2, 3, 4];
console.log(head); // 1
console.log(rest); // [2, 3, 4]
2. 객체 디스트럭처링 할당
- 객체 프로퍼티를 변수로 쉽게 추출하는 문법임
- 프로퍼티 이름과 변수 이름이 동일해야 자동 매칭됨
const user = { name: 'Alice', age: 25 };
const { name, age } = user;
console.log(name, age); // Alice 25
프로퍼티 이름 변경
- 다른 변수명으로 할당 가능함
const { name: userName, age: userAge } = user;
console.log(userName, userAge); // Alice 25
기본값 할당
- 프로퍼티가 undefined이면 기본값 사용함
const { city = 'Seoul' } = user;
console.log(city); // Seoul
중첩 객체 디스트럭처링
- 중첩된 객체 프로퍼티 추출 가능함
const person = { info: { firstName: 'Bob', lastName: 'Smith' } };
const { info: { firstName, lastName } } = person;
console.log(firstName, lastName); // Bob Smith
나머지 프로퍼티 할당(Rest)
- 나머지 프로퍼티를 객체로 모아 할당 가능함
const { name: n, ...others } = { name: 'Alice', age: 25, city: 'Seoul' };
console.log(n); // Alice
console.log(others); // { age: 25, city: 'Seoul' }
Set과 Map
1. Set
- Set 객체는 중복되지 않는 유일한 값들의 집합임
- 원시값과 객체 참조 모두 저장 가능함
- 삽입 순서를 기억함
const set = new Set([1, 2, 3, 3]);
console.log(set); // Set(3) {1, 2, 3}
주요 메서드
- set.add(value) : 값 추가
- set.has(value) : 값 존재 여부 확인
- set.delete(value) : 특정 값 삭제
- set.clear() : 모든 요소 제거
- set.size : 요소 개수 반환
const set = new Set();
set.add(1);
set.add(2);
console.log(set.has(1)); // true
set.delete(1);
console.log(set.size); // 1
Set 순회
- for...of, forEach 모두 사용 가능함
- keys(), values(), entries() 메서드 제공함
const set = new Set([1, 2, 3]);
for (const val of set) {
console.log(val);
}
활용
- 배열 중복 제거에 유용함
const numbers = [1, 2, 2, 3];
const unique = [...new Set(numbers)];
console.log(unique); // [1, 2, 3]
2. Map
- Map 객체는 키-값 쌍으로 이루어진 컬렉션임
- 키에는 객체, 함수, 원시값 모두 가능함
- 삽입 순서를 기억함
const map = new Map();
map.set('key1', 'value1');
map.set('key2', 'value2');
console.log(map.get('key1')); // value1
주요 메서드
- map.set(key, value) : 키-값 쌍 추가
- map.get(key) : 키에 해당하는 값 반환
- map.has(key) : 키 존재 여부 확인
- map.delete(key) : 키와 값 삭제
- map.clear() : 모든 요소 제거
- map.size : 요소 개수 반환
const map = new Map();
map.set('a', 1);
map.set('b', 2);
console.log(map.has('a')); // true
map.delete('a');
console.log(map.size); // 1
Map 순회
- for...of문, forEach 메서드 사용 가능함
- keys(), values(), entries() 메서드 제공함
const map = new Map([
['name', 'Alice'],
['age', 25]
]);
for (const [key, value] of map) {
console.log(key, value);
}
객체와의 차이점
- 객체는 문자열, 심벌만 키로 사용 가능함
- Map은 키 타입 제한 없음
- 요소 개수는 map.size 사용, 객체는 Object.keys(obj).length 사용
const obj = { a: 1 };
obj[1] = 'number key';
console.log(obj); // { '1': 'number key', a: 1 }
const map = new Map();
map.set(1, 'number key');
map.set({x: 10}, 'object key');
console.log(map);
'개발' 카테고리의 다른 글
vercel 로 배포 및 CI/CD 파이프라인 구축하기(배포 자동화) (2) | 2025.08.28 |
---|---|
[모던 자바스크립트 DeepDive] Js 심화 스터디 week 8 (3) | 2025.08.27 |
[모던 자바스크립트 DeepDive] Js 심화 스터디 week 6 (1) | 2025.08.10 |
[모던 자바스크립트 DeepDive] Js 심화 스터디 week 05 (2) | 2025.07.28 |
타입스크립트의 사용 이유와 동작 원리 (2) | 2025.07.23 |