[modern JS Deep Dive] - 33장 . 7번째 데이터 타입 Symbol

유선향·2025년 1월 18일
0

<modern_JS_Deep_Dive>

목록 보기
30/44

심벌이란?

  • ES6 에서 도입된 변경 불가능한 원시 타입의 값이다.
  • 심벌 값은 다른 값과 중복되지 않는 유일무이한 값이다.
  • 주로 이름의 충돌 위험이 없는 유일한 프로퍼티 키를 만들기 위해 사용한다.

심벌 값의 생성

Symbol 함수

  • 리터럴 표기법을 통해 생성할수 없고, Symbol 함수를 호출하여 생성해야 한다.
  • 이때 생성된 심벌 값은 외부로 노출되지 않아 확인할 수 없으며, 다른 값과 절대 중복되지 않는 유일무이한 값이다.
  • 심벌 값도 문자열, 숫자, 불리언과 같이 객체 처럼 접근하면 암묵적으로 래퍼 객체를 생성한다.
//기본 방식
const test = Symbol()

const test1 = Symbol('test')
const test2 = Symbol('test')
//인수로 전달하는 문자열은 디버깅 용이며, 심벌 값 생성에 어떠한 영향도 주지 않는다.

test === test2 //false

심벌과 상수

  • 아래 예제 처럼 상수 값에 의미가 있는게 아니라 상수 이름 자체에 의미가 있는 경우가 있다.
  • 이때 상수 값이 변경 될 수도 있고, 다른 변수값과 중복될수도 있다.
  • 이러한 경우 변경,중복될 가능성이 있는 무의미한 상수 대신 중복될 가능성이 없는 심벌값을 사용할 수 있다.
const d = {
	UP : Symbol('up'),
	DOWN : Symbol('down'),
	LEFT : Symbol('left'),
	RIGHT : Symbol('right'),
}

const myd = d.UP

심벌과 프로퍼티 키

심벌을 프로퍼티 키로 사용하기

  • 빈 문자열을 포함하는 모든 문자열 또는 심벌 값으로 만들 수 있으며, 동적으로 생성 할 수도 있다.
  • 심벌 값을 프로퍼티 키로 사용하려면 프로퍼티 키로 사용할 심벌 값에 대괄호를 사용해야 하고, 프로퍼티에 접근할 때도 마찬가지로 대괄호를 사용해야 한다.
  • 심벌값을 프로퍼티 키로 만들면 다른 프로퍼티 키와 절대 충돌하지 않는다.
const obj = {
	[Symbol.for('test1')] :1 // 프로퍼티 키를 생성
}

obj[Symbol.for('test1')] // 1 

심벌과 프로퍼티 은닉

  • 심벌 값을 프로퍼티 키로 사용하여 생성한 프로퍼티는 for … in 문이나 Object.keys, Object.getOwnPropertyNames 메서드로 찾을 수 없다.
  • 즉, 외부에 노출할 필요가 없는 프로퍼티를 은닉할 수 있다.
  • 하지만, ES6에서 도입된 Object.getOwnPropertySymbols 메서드로 찾을 수 있다.

심벌과 표준 빌트인 객체 확장

  • 일반적으로 표준 빌트인 객체에 사용자 정의 메서드를 직접 추가하여 확장하는 것은 권장하지 않고, 읽기 전용으로 사용하는 것이 좋다.

Symbol 메소드

자주 사용하는 Symbol 메소드

// ✅ Symbol 관련 정리

// 1. Symbol() → 고유한 심볼 생성
const a = Symbol("desc");   // 설명 붙일 수 있음 (디버깅용)
const b = Symbol("desc");
console.log(a === b); // false (항상 고유)

// 2. Symbol.for(key) → 전역 심볼 레지스트리에서 가져오기 (없으면 생성)
const c = Symbol.for("shared");
const d = Symbol.for("shared");
console.log(c === d); // true (같은 키는 같은 심볼)

// 3. Symbol.keyFor(symbol) → 전역 레지스트리에 등록된 심볼의 키 찾기
console.log(Symbol.keyFor(c)); // "shared"
console.log(Symbol.keyFor(a)); // undefined (Symbol()로 만든 건 전역 레지스트리에 없음)

// 4. Object.getOwnPropertySymbols(obj) → 객체 속성 중 심볼 키만 가져오기
const obj = {};
const sym = Symbol("secret");
obj[sym] = "hidden value";
obj.name = "Min";
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(secret) ]
console.log(Object.keys(obj)); // ['name']

// 5. Reflect.ownKeys(obj) → 모든 키(문자열 + 심볼) 가져오기
console.log(Reflect.ownKeys(obj)); // ['name', Symbol(secret)]

// ------------------------------
// ✅ Well-known Symbols (JS 내부 동작 커스터마이징 가능)

// Symbol.iterator → for...of 동작 정의
const arr = [1, 2, 3];
const it = arr[Symbol.iterator]();
console.log(it.next()); // { value: 1, done: false }

// Symbol.asyncIterator → for await...of 동작 정의
const asyncIterable = {
  async *[Symbol.asyncIterator]() {
    yield "A"; yield "B";
  }
};
(async () => {
  for await (const v of asyncIterable) console.log(v); // A, B
})();

// Symbol.toString 
console.log(a.toString()) // Symbol('tag')

// Symbol.toStringTag → 객체의 [object ...] 태그 커스터마이징
class Dog {
  get [Symbol.toStringTag]() {
    return "Puppy";
  }
}
console.log(Object.prototype.toString.call(new Dog())); // [object Puppy]

// Symbol.hasInstance → instanceof 동작 커스터마이징
class MyClass {
  static [Symbol.hasInstance](obj) {
    return obj.type === "custom";
  }
}
console.log({ type: "custom" } instanceof MyClass); // true

// Symbol.toPrimitive → 객체의 원시값 변환 규칙
const money = {
  value: 1000,
  [Symbol.toPrimitive](hint) {
    if (hint === "number") return this.value;
    if (hint === "string") return `$${this.value}`;
    return this.value;
  }
};
console.log(+money); // 1000 (number context)
console.log(`${money}`); // $1000 (string context)

// Symbol.isConcatSpreadable → concat 동작 제어
const arr1 = [1, 2];
const arr2 = [3, 4];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr1.concat(arr2)); // [1, 2, [3,4]]

0개의 댓글