Symbol

안병욱·2022년 6월 5일
0

자바스크립트는 객체 프로퍼티 키를 오직 문자형과 심볼형만을 허용!

  • 숫자형,불린형 모두 불가능

심볼

‘심볼(symbol)’은 유일한 식별자(unique identifier)를 만들고 싶을 때 사용

Sybol() 생성

let id = Symbol();  // 심볼생성

id 라는 심볼을 만들 때 심볼 이름이라 불리는 설명을 붙일 수도 있다.

심볼 이름은 디버깅 시 아주 유용하다.

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

심볼은 유일성이 보장되는 자료형이기 때문에, 설명이 동일한 심볼을 여러 개 만들어도 각 심볼값은 다르다. 심볼에 붙이는 설명(심볼 이름)은 어떤 것에도 영향을 주지 않는 이름표 역할만을 한다.

설명이 같은 심볼 두 개를 만들고 비교를 해보면, 동일 연산자(==)로 비교 시 false가 반환되는 것을 확인할 수 있다.

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

console.log(id1 == id2);  // false
console.log(id1 === id2);  // false

자바스크립트에서의 심볼은 Ruby 등의 언어에서도 유사한 개념을 사용하는데, 자바스크립트의 심볼은 다른 언어들과의 심볼과 다르니 혼동하지 말아야 한다.

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

자바스크립트에선 문자형으로의 암시적 형 변환이 자유롭게 일어나는 편이다.

alert 함수가 거의 모든 값을 인자로 받을 수 있는 이유가 그 때문인데, 심볼은 예외이다. 심볼형 값은 다른 자료형으로 암시적 형 변환(자동 형변환)이 되지 않는다.

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)

만약 심볼의 설명만 보여주고 싶다면 symbol.description 프로퍼티를 이용하면 됩니다.

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

이때 symbol.description 프로퍼티를 사용하면 결과 값은 String으로 결과 값을 리턴한다.

if(id1.description == "id"){
    console.log("같다");
}else {
    console.log("다르다");
}

// 같다

‘숨김’ 프로퍼티

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

서드파티 코드 : 플러그인 이나 라이브러리에서 가져온 코드, 제3자가 쓴 코드

서드파티 코드에서 가지고 온 user 라는 객체가 여러 개 있고, user 를 이용해 어떤 작업을 해야 하는 상황이라고 가정 할 때, user 에 식별자를 붙여보도록 하자.

let user = {
	name: "John"
}

let id = Symbol("id"):

user[id] = 1;

console.log(user[id]); // 심볼을 키로 사용해 데이터에 접근이 가능

객체에서 문자열 “id” 를 키로 사용해도 되는데 Symbol(”id”)를 사용 하는 이유가 무엇일까?

user 는 서드파티 코드에서 가지고 온 객체이므로 함부로 새로운 프로퍼티를 추가할 수 없습니다. 그런데 심볼은 서드파티 코드에서 접근 할 수 없기 때문에, 심볼을 사용하면 서드파티 코드가 모르게 user 에 식별자를 부여할 수 있다.

예시를 들어보자면 user 라는 객체가 있고 그안에 id라는 값이 있다고 가정을 해보자.

let user = { id : "ByeongUk")
let id = Symbol("id");
user[id] = "병욱";

이런씩으로 값을 넣게 되면, 결과 값이 어떻게 나올까? 값을 한번 살펴보겠다.

let user = {id : "Byeonguk"};
let id = Symbol("id");
console.log(user);
// {id : 'Byeonguk' }

user[id] = "병욱";   // user라는 객체에 심볼 값 대입
//'병욱'
console.log(user);
// {id: "Byeonguk',Symbol(id): '병욱'}

user 라는 객체의 값이 키가 id가 2개이지만 서로 같다고 인식 하지 않게 된다.

이렇게 심볼은 유일성이 보장이 되어서 우리가 만든 키와 제3의 스크립트에서 만든 식별자가 충돌하지 않는다.

Symbols in a literal

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

let id = Symbol("id");

let user = {
	name: "John",
	[id]: 123
}

id: 123 이라고 하면, 심볼 id가 아닌 문자열 “id”가 키가 됩니다.

Symbols is for…in exclusion(심볼은 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.keys(user) 에서도 키가 심볼인 프로퍼티는 배제

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

console.log(Object.keys(user));
// []

Object.assign({},user)

  • 키가 심볼인 프로퍼티를 배제 하지 않고 객체내 모든 프로퍼티를 복사

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

전역 심볼

심볼은 이름이 같더라도 모두 별개로 취급된다. 그런데 이름이 같은 심볼이 같은 개체를 가리키길 원하는 경우가 있다. 전역 심볼 레지스트리는 이런 경우를 위해 만들어 졌다.

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

레지스트리 안에 있는 심볼을 읽거나, 새로운 심볼을 생성하려면 Symbol.for(key) 을 사용하면 된다.

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

let id = Symbol.for("id"); 만약 심볼이 존재하지 않으면 새로 생성
let idAgain = Symbol.for("id") // 동일한 이름을 이용해 심볼을 다시 읽는다.
console.log(id === idAgain); // true

전역 심볼 레지스트리 안에 있는 심볼은 전역 심볼이라고 불린다. 어플리케이션에서 광범위하게 사용해야 하는 심볼이라면 전역 심볼을 사용하자!!

0개의 댓글