심볼형

김하은·2023년 5월 7일
0

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

심볼 : 원시형. 유일무이한 식별자를 만들고 싶을 때 사용

심볼 => 유일한 식별자를 만들고 싶을 때 사용.
Symbol()을 사용하면 심볼값을 만들 수 있다.

// id는 새로운 심볼이 됩니다.
let id = Symbol();	

심볼을 만들 시 심볼 이름이라고 불리는 설명을 붙일 수도 있다.
심볼 이름은 디버깅시 유용하다.

/ 심볼 id에는 "id"라는 설명이 붙습니다.
let id = Symbol("id");

심볼은 유일성이 보장되는 자료형이다. 때문에 설명이 동일한 심볼을 여러개 만들더라도 각 심볼의 값은 다르다.( 심볼의 설명 = 심볼 이름 은 이름표역할만 한다.)

설명이 같은 심볼을 두개 만들고 동일연산자(일치연산자 ==)를 사용해 비교하면 false가 나오게 된다.

let id1 = Symbol("id");
let id2 = Symbol("id");

alert(id1 == id2); // false

자바스크립트의 심볼은 다른 언어들에서 쓰이는 심볼과는 다르기에 혼동하면 안된다.


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

자바스크립트에서는 문자형으로 형변환이 비교적 자유롭게 일어난다. 그러나 여기에 심볼은 예외이다.
심볼형 값은 다른 자료형으로 암시적 형변환이 되지 않는다.

예시로 alert에 들어가면 문자형으로 형변환이 자동적으로 되어 들어가는데 심볼형으로 만든 변수를 넣게되면 자동형변환되지 않아 에러를 발생시킨다.

문자열과 심볼은 근본이 다르기에 우연히라도 서로의 타입으로 변환해서는 안된다고한다.
자바스크립트에서는 언어 차원의 보호장치 를 마련해 심볼형이 다른 형으로 변환되지 않게 한다.

심볼을 반드시 출력해 주어야 한다면 String메서드를 명시해주면 된다.

let id = Symbol("id");
alert(id.toString()); // Symbol(id)가 얼럿 창에 출력됨

symbol.description 프로퍼티를 이용하면 설명만 보여주는 것도 가능

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

심볼을 이용해 숨김 프로퍼티 만들기.

심볼을 이용하면 숨김 프로퍼티를 만들 수 있다.
이 숨김 프로퍼티 라는 것은 외부코드에서 접근이 불가하고 값도 덮어쓸 수 없는 프로퍼티이다.

서드파티코드(외부에서 가져온 코드)에서 가지고 온 user라는 객체 여러개가 있고, 이것을 이용해 작업을 해야하는 상황이 있다고 가정하자.

user에 식별자를 붙인다.
식별자는 심볼을 이용해 만든다.

let user = { // 서드파티 코드에서 가져온 객체
  name: "John"
};

let id = Symbol("id");

user[id] = 1;

alert( user[id] ); // 심볼을 키로 사용해 데이터에 접근할 수 있습니다.

=> 문자열 "id"가 아니라 심볼을 키로 사용하였는데 이유가 무엇일까?

user는 외부에서 가져온 객체이므로 함부로 새로운 프로퍼티를 추가할 수는 없다.
그런데 심볼은 서드파티코드(외부..'')에서 접근이 안되기때문에 심볼을 사용한다면 서드파티 코드가 모르게 user에 식별자를 부여할 수 있다.

다른 상황도 있을 수 있다.
다른 스크립트(자바스크립트 라이브러리 등 제3의 스크립트)에서 user를 식별해야 하는 상황이 벌여졌다.
user의 원천인 서드파티코드, 현재 작성중인 스크립트, 다른 스크립트(제 3의 스크립트..)가 각자의 코드도 모른체 user를 식별해야하는 상황.

제3의 스크립트에서는 Symbol("id")를 사용해 전용 식별자를 만들어 사용할 수 있다.

심볼은 유일성이 보장된다.
우리가 만든 식별자와 제3의 스크립트에서 만든 식별자가 충돌하지 않는다.(이름이 같더라도말이다.)
만약 심볼대신 문자열 "id"를 사용한다면 충돌할 가능성이 있다.

심볼 리터럴

객체 리터럴 {...}를 이용해 객체를 만들었다면 대괄호를 사용해 심볼키를 만들어야한다.

let id = Symbol("id");

let user = {
  name: "John",
  [id]: 123 // "id": 123은 안됨
};

심볼 for...in

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

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

for (let key in user) alert(key); // name과 age만 출력되고, 심볼은 출력되지 않습니다.

// 심볼로 직접 접근하면 잘 작동합니다.
alert( "직접 접근한 값: " + user[id] );

Object.key(user) 에서도 키가 심볼인 프로퍼티는 배제된다.
'심볼형 프로퍼티 숨기기(hiding symbolic property)'라 불리는 이런 원칙 덕분에 외부 스크립트나 라이브러리는 심볼형 키를 가진 프로퍼티에 접근하지 못한다.

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

이는 의도적으로 설계된 것입니다. 객체를 복사하거나 병합할 때, 대개 id 같은 심볼을 포함한 프로퍼티 전부를 사용하고 싶어 할 것이라는 생각에서 이렇게 설계되었습니다.

전역심볼

심볼은 이름이 같더라도 모두 별개이다. 그런데 이름이 같은 심볼이 같은 개체를 가리키기를 원하는 경우도 있다.

따라서 전역심볼레지스트리라는 것이 만들어졌다.
전역심볼레지스트리 안에 심볼을 만들고 해당 심볼에 접근하면 이름이 같은 경우 항상 동일한 심볼을 반환하는 것이다.

레지스트리 안에 있는 심볼을 읽거나, 새로운 심볼을 생성하기 위해서는 Symbol.for(key)를 사용한다.(전역 심볼을 찾을때 사용하는 메서드)

이 메서드를 호출하면 key인 심볼을 반환헌다. 조건에 맞는 심볼이 레지스트리 안에 없다면 새로운 Symbol(key)를 만들고 레지스트리 안에 저장한다.

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

// 동일한 이름을 이용해 심볼을 다시 읽습니다(좀 더 멀리 떨어진 코드에서도 가능합니다).
let idAgain = Symbol.for("id");

// 두 심볼은 같습니다.
alert( id === idAgain ); // true

전역 심볼 레지스트리 안에 있는 심볼을 전역심볼이라고 부른다.
광범위하게 사용할 심볼이라면 전역심볼을 사용하도록 한다.

Symbol.for(key) <==> Symbol.keyFor

전역심볼을 찾는(찾고, 없으면 생성함) 메서드 Symbol.for(key)와 반대되는 메서드가 바로 Symbol.keyFor이다.
Symbol.keyFor(sym) 을 사용해 이름(= 설명)을 얻을 수 있다.

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

// 심볼을 이용해 이름을 얻음
alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id

단, 검색범위가 전역심볼레지스트리 이기에 전역심볼이 아닌 심볼에는 사용할 수 없다.
전역심볼이 아닌데 Symbol.keyFor(sym) 을 사용한다면 undefined를 반환한다.
전역 심볼이 아닌 모든 심볼은 description프로퍼티가 존재해 일반심볼에서 이름(= 설명)을 얻으려면 description을 사용한다.

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

alert( Symbol.keyFor(globalSymbol) ); // name, 전역 심볼
alert( Symbol.keyFor(localSymbol) ); // undefined, 전역 심볼이 아님

alert( localSymbol.**description** ); // name

시스템 심볼

자바스크립트 내부에서 사용되는 심볼을 시스템 심볼이라고 한다.
이것을 활용하면 객체를 미세 조정하는것이 가능하다.

명세서 내의 표, 잘 알려진 심볼(well-known symbols)에서 어떤 시스템 심볼이 있는지 살펴보세요.

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

0개의 댓글