들어가며

자바스크립트를 공부하던 중, ES6부터 Symbol이라는 데이터타입이 추가되었다는 사실을 알았다. Symbol이 대체 뭘까?

 

 

 

Symbol

  • Symbol은 ES6에서 도입된 고유하고 변경할 수 없는 값을 생성하는 원시(primitive) 데이터 타입이다.
  • 다른 원시 타입(숫자, 문자열, 불리언 등)과 다르게, 심볼은 유일한 식별자로 사용되며 객체의 프로퍼티 키로 주로 활용된다.
  • 심벌 이외의 원시 값은 리터럴을 통해 생성하지만 심벌은 Symbol 함수를 호출해 생성한다.
  • 이때 생성된 심벌값은 외부에 노출되지 않으며, 다른 값과 절대 중복되지 않는 유일무이한 값이다.

 

 

 

1. 객체 프로퍼티의 고유한 키 생성

문자열 키는 충돌할 위험이 있지만 Symbol을 사용하면 절대 중복되지 않는 고유한 프로퍼티 키를 만들 수 있다. 같은 키 이름 "id"를 사용했더라도 각각 다른 Symbol이므로 충돌이 발생하지 않기 때문에, 외부에서 실수로 접근하거나 덮어쓸 위험이 줄어든다.

 

예제 1 (문자열 키 충돌)

const obj = {
  id = "123",
};

obj[id] = "456";  // 기존 프로퍼티가 덮어씌어짐

console.log(obj);
// 실행결과
{ id: '456' }

 

예제 2 (Symbol 사용)

const id1 = Symbol("id");
const id2 = Symbol("id");  // 같은 설명을 넣어도 완전히 다른 Symbol

const obj = {
  [id1]: "123",
  [id2]: "456",
};

console.log(obj[id1]);
console.log(obj[id2]);
console.log(obj);
// 실행결과
123
456
{ [Symbol(id)]: '123', [Symbol(id)]: '456' }

 

 

 

2. 프로퍼티를 은닉(숨김)해 외부 접근 방지

객체의 일반 프로퍼티는 for...in 또는 Object.keys() 등을 사용하면 모두 나열되지만 Symbol을 프로퍼티 키로 사용하면 기본적으로 숨겨지므로(은닉), 외부 접근을 방지할 수 있다.

 

예제 3 (Symbol로 숨겨진 프로퍼티)

const secretKey = Symbol("secret");

const user = {
    name: "velkoz",
    age: 20,
    [secretKey]: "떡볶이",
};

console.log(Object.keys(user));
console.log(Object.getOwnPropertyNames(user));
// 실행결과
[ 'name', 'age' ]
[ 'name', 'age' ]

 

 

 

💡 그렇다면 Symbol 타입 변수에 API Key 값을 할당해도 되는 걸까?


결론부터 말하자면, 보안상 적절하지 않다. Symbol은 고유한 값이며, 객체의 프로퍼티 키로 사용할 때 충돌을 방지하는 용도로 쓰이지, 보안적인 목적으로 데이터를 보호하는 기능을 제공하지는 않는다. secretKey는 Ojbect.keys()for...in을 사용해도 보이지 않지만 Object.getOwnPropertySymbols()을 사용하면 Symbol 키를 확인할 수 있다.

console.log(user[secretKey]);
console.log(Object.getOwnPropertySymbols(user));
// 실행결과
떡볶이
[ Symbol(secret) ]

 

Reflect.ownKeys()를 사용하면 Symbol 키까지 포함해서 조회할 수 있다.

 

예제 4

const API_KEY = Symbol("secret"); 
const config = {
  [API_KEY]: "super-secret"
};

console.log(config[API_KEY]);
console.log(Reflect.ownKeys(config));
// 실행결과
super-secret
[ Symbol(secret) ]

 

 

 

3. Symbol.for()를 이용해 전역적으로 공유

Symbol()을 직접 사용하면 매번 새로운 심볼이 생성되지만, Symbol.for()를 사용하면 전역 심볼 레지스트리(Global Symbol Registry)에 등록해 같은 키에 대해 전역적으로 같은 심볼을 참조할 수 있기 때문에 Symbol을 재사용할 수 있다.

 

예제 5

const sym1 = Symbol.for("sharedKey");
const sym2 = Symbol.for("sharedKey");

console.log(sym1 === sym2);
// 실행결과
true

 

 

 

4. 내부 심볼 (Symbols for Built-in Features) 활용

Symbol.iterator를 사용하면 객체에 반복자(iterator)를 추가해 for...of 루프에서 사용할 수 있다.

 

예제 6

class CustomCollection {
  constructor(items) {
    this.items = items;
  }

  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => ({
        value: this.items[index++],
        done: index > this.items.length
      })
    };
  }
}

const collection = new CustomCollection(["a", "b", "c"]);

for (const item of collection) {
  console.log(item);
}
// 실행결과
a
b
c

 

 

 

참고

 

 

 

728x90
반응형

'Language > JavaScript' 카테고리의 다른 글

[JS] Math.random() 보안 취약점과 해결방안  (0) 2025.03.15
[JS] forEach(console.log)  (0) 2025.03.02