본문 바로가기

모던 자바스크립트

4.7 심볼형

📢 자바스크립트는 객체 프로퍼티 키로 문자형심볼형만을 허용한다. 

 

심볼(Symbol)

📢 유일한 식별자(unique identifier)를 만들고 싶을 때 사용한다. 

let id = Symbol();

 

◾️ 심볼을 만들 때 심볼 이름이라 불리는 설명을 붙일 수도 있다. 디버깅시 아주 유용

let id = Symbol('id');

◾️ 심볼은 유일성이 보장되는 자료형이기 때문에, 설명이 동일한 심볼을 여러 개 만들어도 각 심볼값은 다르다. 

let suzu = Symbol('name');
let ruru = Symbol('name');

console.log(suzu == ruru); // false

 

⚠️ 심볼은 문자형으로 자동 형 변환되지 않는다. 

 

◾️ 자바스크립트에선 문자형으로의 암시적 형 변환이 비교적 자유롭게 일어나는 편이지만 심볼은 예외

let id = Symbol('id');
alert(id); // TypeError: Cannot convert a Symbol value to a string

◾️ 문자열과 심볼은 근본이 다르다!

◾️ 언어 차원의 보호장치(language guard)를 마련해 심볼형이 다른 형으로 변환되지 않게 막아준다. 

◾️ 심볼을 출력해야 하는 상황에는 .toString() 메서드를 사용한다. 

let id = Symbol('id');
alert(id.toString()); // Symbol(id)

◾️ 심볼의 설명만 출력하고 싶을 때는 description 프로퍼티를 이용한다. 

let id = Symbol('id');
alert(id.description); // id

 

'숨김'  프로퍼티

◾️ 심볼을 이용하면 숨김(hidden) 프로퍼티를 만들 수 있다. 

◾️ 숨김(hidden) 프로퍼티 : 외부 코드에서 접근이 불가능하고 값도 덮어쓸 수 없는 프로퍼티

◾️ 문자열 'id' 대신 Symbol('id')를 사용한 이유

     ◾️ user는 서드파티 코드에서 가지고 온 객체이므로 함부로 새로운 프로퍼티를 추가할 수 없다. 

     ◾️ 심볼은 서드파티 코드에서 접근할 수 없기 때문에 심볼을 사용하면 서드파티 코드가 모르게 user에 식별자를 부여할 수 있다. 

// user에 심볼을 이용해 식별자를 만들어준다.

let user = { // 서드파티 코드에서 가져온 객체
  name: 'suzu'
}

let id = Symbol('id');
user[id] = 1;

console.log( user[id] ); // 1
⚠️ 서드파티

하드웨어 생산자와 직접적인 관계없이 소프트웨어를 개발하는 회사를 서드 파티라고 부른다. 또는 하드웨어 생산자인 모기업과 자사간의 관계 또는 하청관계등 전혀 관련없는 소프트웨어 개발자를 써드 파티라고 부른다.  _ wiki

 

◾️ 서드파티에서 가져온 객체 user, 현재 작성중인 스크립트, 제3의 스크립트(자바스크립트 라이브러리 등)가 각자 서로의 코드도 모른채 user를 식별해야 하는 상황일 때.

◾️ 제 3의 스크립트에선 Symbol('id')을 이용해 전용 식별자를 만들어 사용할 수 있다. 

// ...
let id = Symbol('id');

user[id] = '제3의 스크립트의 id값';

◾️ 이름이 같더라도 심볼은 유일성이 보장되므로 우리가 만든 식별자와 제3의 스크립트에서 만든 식별자가 충돌하지 않는다. 

 

 

객체 리터럴과 심볼

◾️ 객체 리터럴 { ... }을 사용해 객체를 만든 경우, 대괄호를 사용해 심볼형 키를 만들어야 한다. 

◾️ 'id: 123' 이라고 하면, 심볼 id가 아닌 문자열 id가 키가 된다. 

let id = Symbol('id');

let user = {
  name: 'suzu',
  [id]: 123 // 'id:123' X
}

 

심볼은 for...in에서 배제된다. 

◾️ 키가 심볼인 프로퍼티는 for .. in 반복문에서 배제된다. 

let id = Symbol('id');
let user = {
  name: 'suzu',
  age: 30,
  [id]: 123
};

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

// 심볼로 직접 접근
console.log( user[id] ); // 123

◾️ Object.keys(user)에서도 키가 심볼인 프로퍼티는 배제된다. (for...in과 같은 결과)

◾️ 심볼형 프로퍼티 숨기기(hiding symbolic property) 원칙 덕분에 외부 스크립트나 라이브러리는 심볼형 키를 가진 프로퍼티에 접근하지 못한다. 

◾️ Object.assign은 키가 심볼인 프로퍼티를 배제하지 않고 객체 내 모든 프로퍼티를 복사한다. 

let id = Symbol('id');
let user = {
  [id]: 123
};

let clone = Object.assign({}, user);

console.log( clone[id] ); // 123

 

전역 심볼

◾️ 심볼은 이름이 같더라도 모두 별개로 취급되지만 이름이 같은 심볼이 같은 개체를 가리키길 원하는 경우도 있다. 

◾️ 전역 심볼 레지스트리(global symbol registry) : 애플리케이션 곳곳에서 심볼 'id'를 이용해 특정 프로퍼티에 접근해야 할 때 사용

◾️ 전역 심볼 레지스트리 안에 심볼을 만들고 해당 심볼에 접근하면, 이름이 같은 경우 항상 동일한 심볼을 반환해 준다. 

◾️ Symbol.for(key)를 호출하면 이름이 key인 심볼이 반환된다.

◾️ 조건에 맞는 심볼이 레지스트리 안에 없으면 새로운 심볼 Symbol(key)를 만들고 레지스트리 안에 저장한다. 

// 전역 레지스트리에서 심볼을 읽는다. 
let id = Symbol.for('id'); // 심볼이 존재하지 않으면 새로운 심볼을 만든다.

// 동일한 이름을 이용해 심볼을 다시 읽는다. 
let idAgain = Symbol.for('id'); 

console.log( id === idAgain ); // true;

◾️ 전역 심볼 레지스트리 안에 있는 심볼을 전역 심볼이라 부른다. 광범위하게 사용해야 하는 심볼이라면 전역 심볼을 사용한다. 

 

Symbol.keyFor

◾️ Symbol.keyFor(sym) : Symbol.for(key)에 반대되는 메서드. 이름을 얻을 수 있다. 

// 이름을 이용해 심볼을 찾는다. 
let sym = Symbol.for('name');
let sym2 = Symbol.for('id');

// 심볼을 이용해 이름을 얻는다. 
console.log( Symbol.keyFor(sym) ); // name
console.log( Symbol.keyFor(sym2) ); // id

◾️ Symbol.keyFor는 전역 심볼 레지스트리를 뒤져서 해당 심볼의 이름을 얻어낸다. 전역 심볼이 아닌 심볼에는 사용할 수 없다.(undefined를 반환)

◾️ 일반 심볼에서 이름을 얻고 싶으면 description 프로퍼티를 사용한다. 

let globalSymbol = Symbol.for('name');
let localSymbol = Symbol('name');

console.log( Symbol.keyFor(globalSymbol) ); // name
console.log( Symbol.keyFor(localSymbol) ); // undefined

console.log( localSymbol.description ); // name

 

시스템 심볼(system symbol)

◾️ 자바스크립트 내부에서 사용되는 심볼. 시스템 심볼을 활용하면 객체를 미세조정할 수 있다. 

  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.iterator
  • Symbol.toPrimitive
  • 기타 등등...

 

📝 요약

◽️ Symbol은 원시형 데이터로 유일한 식별자를 만드는데 사용된다. 
◽️ Symbol() 메소드를 호출하여 심볼을 만든다. 설명(이름)은 옵션
◽️ 심볼은 이름은 같더라도 값이 항상 다르다. 
◽️ 이름이 같을 때 값도 같길 원한다면 전역 레지스트리를 사용해야한다. 
◽️ Symbol.for(key)는 key라는 이름을 가진 전역 심볼을 반환한다. 
◽️ key라는 이름을 가진 전역 심볼이 없으면 새로운 전역 심볼을 만들어 준다. 
◽️ key가 같다면 Symbol.for는 어디서 호출하든 상관없이 항상 같은 심볼을 반환해준다.

 



📝 오늘 새롭게 배운 내용 📝

 

✅ 심볼은 유니크한 존재다. 

변수처럼 전역 심볼이라는 개념이 존재한다.  

✅ 프로퍼티를 숨기고 싶을 때 사용할 수도 있다. 

✅ 자바스크립트 내부에서 사용되는 심볼이 있다. 

✅ 유스케이스는 이해했지만 실제로 어떻게 쓰일지...?

 

 

 

📌 [JAVASCRIPT_INFO 심볼형]

 

 

심볼형

 

ko.javascript.info

📌 [MDN Symbol]

 

Symbol

Symbol() 함수는 심볼(symbol) 형식의 값을 반환하는데, 이 심볼은 내장 객체(built-in objects)의 여러 멤버를 가리키는 정적 프로퍼티와 전역 심볼 레지스트리(global symbol registry)를 가리키는 정적 메서드

developer.mozilla.org

 

 

 

 

 

 

'모던 자바스크립트' 카테고리의 다른 글

6.1 재귀와 스택  (0) 2020.08.15
4.8 객체를 원시형으로 변환하기  (0) 2020.08.13
4.6 옵셔널 체이닝 '?.'  (0) 2020.08.11
4.5 'new' 연산자와 생성자 함수  (0) 2020.08.10
4.4 메서드와 'this'  (0) 2020.08.08