요즘IT
위시켓
콘텐츠프로덕트 밸리
요즘 작가들컬렉션물어봐
놀이터
콘텐츠
프로덕트 밸리
요즘 작가들
컬렉션
물어봐
놀이터
새로 나온
인기
개발
AI
IT서비스
기획
디자인
비즈니스
프로덕트
커리어
트렌드
스타트업
서비스 전체보기
위시켓요즘IT
고객 문의
02-6925-4867
10:00-18:00주말·공휴일 제외
yozm_help@wishket.com
요즘IT
요즘IT 소개작가 지원
기타 문의
콘텐츠 제안하기광고 상품 보기
요즘IT 슬랙봇크롬 확장 프로그램
이용약관
개인정보 처리방침
청소년보호정책
㈜위시켓
대표이사 : 박우범
서울특별시 강남구 테헤란로 211 3층 ㈜위시켓
사업자등록번호 : 209-81-57303
통신판매업신고 : 제2018-서울강남-02337 호
직업정보제공사업 신고번호 : J1200020180019
제호 : 요즘IT
발행인 : 박우범
편집인 : 노희선
청소년보호책임자 : 박우범
인터넷신문등록번호 : 서울,아54129
등록일 : 2022년 01월 23일
발행일 : 2021년 01월 10일
© 2013 Wishket Corp.
로그인
요즘IT 소개
콘텐츠 제안하기
광고 상품 보기
개발

자바스크립트에선 왜 심볼(Symbol)을 사용할까?

효빈
8분
2일 전
2.7K
에디터가 직접 고른 실무 인사이트 매주 목요일에 만나요.
newsletter_profile0명 뉴스레터 구독 중

자바스크립트에서 우리가 흔히 사용하는 자료형에는 문자열(string), 숫자(number), 불리언(boolean) 등이 있습니다. 하지만 ES6(ECAMScript2015)부터는 새로운 원시 타입인 Symbol이 도입되었고, 이는 비교적 덜 알려져 있지만 매우 중요한 역할을 합니다.

 

Symbol은 객체 프로퍼티 키로 사용될 수 있으며, 고유한 식별자를 생성해 충돌 없는 키를 만들 수 있다는 점에서 특히 유용합니다. 게다가 이 심볼은 객체의 내부 동작을 오버라이드하는 데에도 활용되기 때문에, 단순한 “희귀한 키” 이상의 가치를 가집니다. 이번 글에서는 Symbol 타입의 정의부터 활용 사례, 그리고 자바스크립트 언어 내부의 동작에 어떻게 연결되는지까지 자세히 살펴보겠습니다.

 

<출처: 한 번에 끝내는 자바스크립트>
 

Symbol이란 무엇인가?

Symbol은 자바스크립트에서 새롭게 도입된 원시 타입으로, 기존의 문자열, 숫자, 불리언처럼 값을 직접 나타내기보다는, 고유한 식별자(unique identifier) 역할을 하는 값이라고 할 수 있습니다. 특히 객체의 키로 사용할 수 있으며, 그 키가 외부 코드와 절대로 충돌하지 않는다는 점에서 매우 유용합니다.

 

보통 객체의 키는 문자열이나 숫자 등을 사용하지만, 복잡한 코드 환경에서는 같은 이름의 키가 중복될 가능성이 존재합니다. 이런 문제를 방지하기 위해 등장한 것이 바로 Symbol입니다. 각각의 Symbol은 생성될 때마다 완전히 독립적인 값이 되며, 이 값은 디버깅을 위한 설명만을 가질 뿐, 내부적으로는 절대 중복되지 않습니다.

 

1) Symbol의 정의와 기본 사용법

Symbol은 Symbol()이라는 함수로 생성합니다. 이때 선택적으로 설명 문자열(description)을 넘길 수 있으며, 이 설명은 디버깅이나 로그 출력에서 사용됩니다. 하지만 같은 설명을 사용하더라도 생성된 심볼 값은 서로 다릅니다.

 

const sym1 = Symbol();
const sym2 = Symbol("description");

console.log(sym1); // Symbol()
console.log(sym2); // Symbol(description)

 

이처럼 Symbol() 함수는 고유한 값을 반환합니다. 설명이 같더라도 실제 심볼은 완전히 다르기 때문에, 아래의 비교 false가 됩니다.

 

console.log(Symbol("id") === Symbol("id")); // false

 

위 코드에서 “id”라는 동일한 설명을 사용해 두 개의 Symbol을 생성했지만, 결과를 보면 false입니다. 이처럼 Symbol은 호출할 때마다 새로운 고유 식별자를 생성하므로, 절대로 중복될 일이 없습니다. 이것이 심볼이 “충돌 없는 안전한 키”로 활용되는 가장 큰 이유입니다.

 

2) 심볼의 고유성

Symbol의 핵심은 고유성입니다. Symbol()을 호출할 때마다 자바스크립트 엔진은 이전에 만든 어떤 심볼과도 중복되지 않는 새로운 값을 생성합니다. 이 특성 덕분에 객체에 속성을 추가할 때, 외부 코드나 라이브러리와의 충돌을 완전히 피할 수 있습니다.

 

일반적인 문자열 키를 사용하면, 다른 코드에서 동일한 이름을 사용하는 순간 기존 속성이 덮어씌워지는 문제가 발생할 수 있습니다. 반면 Symbol을 키로 사용하면, 외부에서 의도치 않게 접근하거나 수정하는 것을 방지할 수 있습니다.

 

예를 들어, 아래 코드를 보겠습니다.

 

const symA = Symbol("userId");
const symB = Symbol("userId");

const user = {
  [symA]: 123,
  [symB]: 456
};

console.log(user[symA]); // 123
console.log(user[symB]); // 456
console.log(user); // { [Symbol(userId)]: 123, [Symbol(userId)]: 456 }

 

이 코드에서 symA와 symB는 동일한 설명 “userId”를 갖지만, 서로 다른 고유한 Symbol 값입니다. 따라서 객체 user에는 충돌 없이 두 개의 속성이 각각 별개의 키로 저장됩니다. 만약 일반 문자열 “userId”를 사용했다면 하나의 값이 덮어씌워졌을 것입니다.

 

이처럼 심볼은 외부 코드와의 간섭을 막고, 안전하게 식별자를 정의할 수 있도록 도와줍니다. 특히 라이브러리나 프레임워크처럼 범용적으로 사용되는 코드에서는 키 충돌 방지를 위해 Symbol을 사용하는 것이 좋은 선택이 됩니다.

 

 

심볼을 객체의 키로 사용할 때의 특징

Symbol은 고유성과 함께 객체 프로퍼티 키로서의 특별한 동작을 가지고 있습니다. 우리가 일상적으로 사용하는 for…in문이나 Object.keys() 같은 메서드에서는 심볼 키가 무시되기 때문에, 일종의 “숨겨진 프로퍼티”처럼 작동할 수 있습니다. 그러나 완전히 은닉된 것은 아니며, 원한다면 여전히 접근이 가능합니다.

 

1) for…in, Object.keys 등에서 제외되는 이유

자바스크립트에서는 객체의 키들을 반복하거나 나열할 때 보통 for…in, Object.keys(), JSON.stringify() 등을 사용합니다. 그런데 Symbol을 키로 사용하는 경우, 이러한 메서드들은 해당 키를 무시합니다. 이는 의도된 설계로, 외부에 노출되지 않아야 할 속성이나 내부적인 설정을 저장할 때 Symbol이 유용하게 작동하도록 하기 위함입니다.

 

const secret = Symbol("secret");

const user = {
  name: "Alice",
  age: 30,
  [secret]: "hidden value"
};

for (let key in user) {
  console.log(key); // name, age
}

console.log(Object.keys(user)); // [ 'name', 'age' ]
console.log(JSON.stringify(user)); // {"name":"Alice","age":30}

 

위 코드에서 secret 심볼로 정의된 키는 for…in과 Object.keys()에 나타나지 않습니다. 마치 해당 속성이 존재하지 않는 것처럼 보이죠. 이를 통해 라이브러리나 프레임워크 내부에서 사용자 코드와 충돌하지 않도록 숨겨진 데이터를 안전하게 저장할 수 있습니다.

 

2) 완전한 은닉은 아니다: Object.getOwnPropertySymbols

심볼이 일반적인 키 반복에서 제외되기는 하지만, 절대로 완전히 숨겨지는 것은 아닙니다. 자바스크립트는 여전히 해당 객체에 어떤 심볼 키들이 있는지 확인할 수 있는 방법을 제공합니다. 그중 대표적인 메서드가 Object.getOwnPropertySymbols() 입니다.

 

const secret = Symbol("secret");

const user = {
  name: "Alice",
  [secret]: "hidden value"
};

const symbols = Object.getOwnPropertySymbols(user);
console.log(symbols); // [ Symbol(secret) ]
console.log(user[symbols[0]]); // hidden value

 

이처럼 Object.getOwnPropertySymbols()를 사용하면 객체 내부의 모든 심볼 키를 배열로 확인할 수 있고, 해당 키를 통해 값에 접근하는 것도 가능합니다. 따라서 심볼을 보안 수단으로 쓰는 것은 적절하지 않으며, 은닉 목적의 보조 도구로 이해하는 것이 더 정확합니다.

 

 

Symbol.for와 Symbol.keyFor

지금까지 살펴본 Symbol은 호출될 때마다 새로운 고유값을 생성하는 특징이 있습니다. 하지만 경우에 따라 공통의 심볼 값을 공유해야 하는 상황도 존재합니다. 이를 위해 자바스크립트는 전역 심볼 레지스트리를 제공하며, 여기에 저장된 심볼을 통해 값을 재사용하거나 조회할 수 있도록 합니다.

 

1) 전역 심볼 레지스트리란?

전역 심볼 레지스트리는 자바스크립트 엔진 내부에 존재하는 저장소로, Symbol.for(key)를 통해 접근합니다. 이 메서드는 동일한 키를 주면 항상 같은 심볼을 반환하므로, 서로 다른 모듈이나 파일에서도 같은 심볼을 공유할 수 있게 해줍니다.

 

const globalSym1 = Symbol.for("app.config");
const globalSym2 = Symbol.for("app.config");

console.log(globalSym1 === globalSym2); // true

 

위 예시에서 globalSym1과 globalSym2는 같은 키 “app.config”를 사용했기 때문에 동일한 심볼을 참조하게 됩니다. 이는 고유성이 아니라, 재사용 가능한 전역 식별자가 필요한 상황에서 유용하게 사용됩니다.

 

2) Symbol.keyFor로 거꾸로 찾기

전역 레지스트리에 등록된 심볼은 Symbol.keyFor() 메서드를 사용해 거꾸로 키값을 찾을 수 있습니다. 이를 통해 특정 심볼이 어떤 키로 등록되었는지를 알아낼 수 있습니다.

 

const sym = Symbol.for("user.token");
console.log(Symbol.keyFor(sym)); // "user.token"

 

하지만 일반 Symbol은 레지스트리에 등록되지 않기 때문에 Symbol.keyFor()로는 찾을 수 없습니다.

 

const localSym = Symbol("user.token");
console.log(Symbol.keyFor(localSym)); // undefined

 

이처럼 전역 심볼 레지스트리와 일반 심볼은 다르게 동작하며, 각각의 용도에 맞게 선택하여 사용해야 합니다. 일반 심볼은 철저한 고유성이 필요할 때, 전역 심볼은 모듈 간 식별자 공유가 필요할 때 유용합니다.

 

 

자바스크립트 내장 심볼의 역할

Symbol은 단순히 객체 키로 사용되는 식별자 그 이상의 역할을 합니다. 자바스크립트 엔진 자체에서 사용하는 내장 심볼(built-in Symbol)이 존재하며, 이를 통해 객체가 자바스크립트 언어 내부 동작에 개입하거나 오버라이드 할 수 있습니다.

 

1) 대표적인 내장 심볼들

ES6 이후 표준에서 정의된 여러 내장 심볼이 있으며, 이들은 객체의 기본 동작 방식을 사용자 정의로 바꾸는 데 사용됩니다. 대표적인 내장 심볼은 다음과 같습니다.

 

<출처: 작가>

 

예를 들어, 배열처럼 동작하는 사용자 정의 객체를 만들고 싶다면 Symbol.iterator를 구현할 수 있습니다.

 

const iterable = {
  data: [1, 2, 3],
  [Symbol.iterator]() {
    let i = 0;
    return {
      next: () => ({
        value: this.data[i++],
        done: i > this.data.length
      })
    };
  }
};

for (const val of iterable) {
  console.log(val); // 1, 2, 3
}

 

이처럼 심볼은 자바스크립트 엔진과 상호작용할 수 있는 “비밀 통로” 같은 역할을 하며, 내장 심볼을 활용하면 객체가 언어 구조에 더 깊숙이 관여할 수 있습니다.

 

2) 내장 심볼로 언어 동작 오버라이드하기

Symbol은 언어 차원에서의 확장을 가능하게 합니다. 예를 들어, Symbol.toPrimitive를 사용하면 객체가 숫자나 문자열로 암묵적으로 변환될 때의 동작을 제어할 수 있습니다.

 

const obj = {
  [Symbol.toPrimitive](hint) {
    if (hint === "number") return 42;
    if (hint === "string") return "hello";
    return null;
  }
};

console.log(+obj); // 42
console.log(`${obj}`); // hello

 

이 코드를 통해, 객체가 상황에 따라 다른 값으로 변환되는 과정을 개발자가 제어할 수 있습니다. Symbol을 통해 내부 동작을 오버라이드함으로써, 사용자 정의 객체가 훨씬 유연하게 동작하게 되는 것이죠.

 

 

마치며

Symbol은 단순한 “희귀한 키” 이상의 의미를 갖는 자바스크립트의 중요한 기능입니다. 고유성과 은닉성을 동시에 갖춘 식별자를 생성할 수 있을 뿐 아니라, 전역 레지스트리를 통한 재사용, 객체 내부 동작 제어 등 다양한 영역에서 활용됩니다. 특히 내장 심볼을 통해 객체의 동작 방식을 직접 오버라이드할 수 있기 때문에, 언어의 고급 기능을 구현할 때 필수적인 요소로 자리 잡고 있습니다.

 

자바스크립트를 깊이 있게 이해하고 싶은 개발자라면, Symbol은 반드시 숙지해야 할 개념 중 하나입니다. 단순한 객체 키를 넘어, 자바스크립트 언어 자체를 확장할 수 있는 강력한 도구로 활용될 수 있기 때문입니다.

 

©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.