[javascript]javascript 심볼형

rondido·2022년 9월 5일
0

Javascript

목록 보기
19/21

심볼형

  • 자바스크립트는 객체 프로퍼티 키로 오직 문자형과 심볼형만을 허용. 숫자형, 불린형 모두 불가능하고 오직 문자형과 심볼형만 가능

  • 지금까지는 프로퍼티 키가 문자형인 경우만 살펴보았습니다. 이번 챕터에선 프로퍼티 키로 심볼값을 사용해 보면서, 심볼형 키를 사용할 때의 이점에 대해 살펴보도록 하겠습니다.


심볼

  • 심볼은 유일한 식벼자를 만들고 싶을 때 사용

  • Symbol()을 사용하면 심볼값을 만들 수 있다.

// id는 새로운 심볼이 됩니다.
let id=Symbol();
  • 심볼을 만들 때 심볼 이름이라 불리는 설명을 붙일 수도 있습니다 .심볼 이름은 디버깅시 아주 유용
// 심볼 id에는 "id"라는 설명이 붙습니다.
let id = Symbol("id");
  • 심볼은 유일성이 보장되는 자료형이기 때문에, 설명이 동일한 심볼을 여러 개 만들어도 각 심볼값은 다릅니다. 심볼에 붙이는 설명(심볼 이름)은 어떤 것에도 영향을 주지 않는 이름표 역할만 함.

  • 설명이 같은 심볼 두 개를 만들고 이를 비교해보겠습니다. 동일 연산자(==)로 비교 시 fasle가 반환

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

console.log(id1 == id2); //false
  • 참고로 Ruby 등의 언어에서도 '심볼'과 유사한 개념을 사용하는데 자바스크립트의 심볼은 이들 언어에 쓰이는 심볼관느 다르기 때문에 혼동하지 마시길 바랍니다.

  • 심볼은 문자형으로 자동 형 변환되지 않습니다.
    • 자바스크립트에선 문자형으로의 암시적 형 변환이 비교적 자유롭게 일어나는 편입니다. console.log함수가 거의 모든 값을 인자로 받을 수 있는 이유가 이 때문이죠. 그러나 심볼은 예외 심볼형 값은 다른 자료형으로 암시적 형 변환(자동 형 변환)되지 않습니다.
let id = Symbol("id");
console.log(id);
  • 문자열과 심볼은 근본이 다르기 때문에 우연히라도 서로의 타입으로 변환돼선 안된다. 자바스크립트에선 '언어 차원의 보호장치'를 마련해 심볼형이 다른형ㅇ로 변환되지 않게 막아줌

  • 심볼을 반드시 출력해줘야 하는 상황이라면 아래와 같이 .toString()메서드를 명시적으로 호출

let id = Symbol("id");
console.log(id.toString()); // Symbol(id)가 얼럿 창에 출력됨
  • symbol.description 프로퍼티를 이용하면 설명만 보여주는 것도 가능
let id = Symbol("id");
console.log(id.description); //id

'숨김' 프로퍼티

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

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

  • 식별자는 심볼을 이용해 만들도록 하겠습니다.

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

user[id] = 1;

console.log(user[id]); // 심볼을 키로 사용해 데이터에 접근할 수 있다.
  • 그런데 문자열 "id"를 키로 사용해도 되는데 Symbol("id")을 사용한 이유가 무엇일까요?

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

  • 상황 하나를 더 가정해보겠습니다. 제3의 스크립트(자바스크립트 라이브러리 등)에서 user를 식별해야 하는 상황이 벌어졌다고 해보죠 user의 원천인 서드파티 코드, 현재 작성 중인 스크립트, 제3의 스크립트가 각자 서로의 코드도 모른 채 user를 식별해야하는 상황이 벌어졌습니다.

  • 제3의 스크립트에선 아래와 같이 Symbol("id")을 이용해 전용 식별자를 만들어 사용할 수 있다.

// ...
let id = Symbol("id");
user[id] = "제3 스크립트 id 값";
  • 심볼은 유일성이 보장되므로 우리가 만든 식별자와 제3의 스크립트에서 만든 식별자가 충돌하지 않습니다. 이름이 같더라도 말이죠

  • 만약 심볼 대신 문자열 "id"를 사용해 식별자를 만들었다면 충돌이 발생할 가능성이 있습니다.

let user ={name:"John"}

//문자열 "id"를 사용해 식별자를 만들었습니다.
user.id = "스크립트 id 값";

// 만약 제3의 스크립트가 우리 스크립트와 동일하게 문자열 "id"를 이용해 식별자를 만들었다면...

user.id = "제3 스크립트 id 값"
// 의도치 않게 값이 덮어 쓰여서 우리가 만든 식별자는 무의미해집니다.

Symbols in a literal

  • 객체 리터럴 {...}를 사용해 객체를 만든 경우, 대괄호를 사용해 심볼형 키를 만듬
let id = Symbol("id");

let user = {
	name:"John",
    [id]: 123 // "id":123은 안됨
}
  • "id: 123"이라고 하면, 심볼 id가 아니라 문자열 "id"가 키가 됩니다.

심볼은 for...in에서 배제됩니다.

  • 키가 심볼인 프로퍼티는 for..in 반복문 배제
let id = Symbol("id");
let user ={
	name: "John",
    age: 30,
    [id]: 123
};

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

// 심볼로 직접 접근하면 잘 작동합니다.
console.log("직접 접근한 값: " + user[id]);
  • Object.keys(user)에서도 키가 심볼인 프로퍼티는 배제 됩니다. '심볼형 프로퍼티 숨기기'라 불리는 이런 원칙 덕분에 외부 스크립트나 라이브러리는 심볼형 키를 가진 프로퍼티에 접근하지 못합니다.
  • 그런데 Object.assign은 키가 심볼인 프로퍼티를 배제하지 않고 객체 내 모든 프로퍼티를 복사
let id = Symbol("id");
let user = {
	[id]"123
};
let clone = Object.assign({},user);
console.log(clone[id]); //123
  • 뭔가 모순이 있는 것 같아 보이지만, 이는 의도적으로 설계된 것 객체를 복사하거나 병합할 때, 대개 id 같은 심볼을 포함한 프로퍼티 전부를 사용하고 싶어 할 것이라는 생각에서 이렇게 설계

전역 심볼

  • 앞서 살펴본 것처럼, 심볼은 이름이 같더라도 모두 별개로 취급 그런데 이름이 같은 심볼이 같은 개체를 가리키길 원하는 경우도 가끔 있음. 애플리케이션 곳곳에서 심볼 "id"를 이용해 특정 프로퍼티에 접근해야 한다고 가정

  • 전역 심볼 레지스트리는 이런 경우를 위해 만들어졌습니다. 전역 심볼 레지스트리 안에 심볼을 만들고 해당 심볼에 접근하면, 이름이 같은 경우 항상 동일한 심볼을 반환

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

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

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

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

// 두 심볼은 같습니다.
console.log( id===idAgin); //true
  • 전역 심볼 레지스트리 안에 있는 심볼 전역 심볼이라고 불립니다. 애플리케이션에서 광범위하게 사용해야 하는 심볼이라면 전역 심볼을 사용

  • Ruby 랑 비슷해 보이네요.

  • ruby 등의 몇몇 언어에선 이름이 같으면 심볼도 같습니다.

  • 자바스크립트에선 전역 심볼에만 이런 특징이 적용


Symbol.keyFor

  • 전역 심볼을 찾을 때 사용되는 Symbol.for(key)에 반대되는 메서드도 있습니다. Symbol.keyfor(sym)를 사용하면 이름을 얻을 수 있다.
// 이름을 이용해 심볼을 찾음
let sym = Symbol.for("name");
let sym2 = Symbol.for("id");

// 심볼을 이용해 이름을 얻음
console.log( Symbol.keyFor(sym) ); // name
console.log( Symbol.keyFor(sym2) ); // id
  • Symbol.keyfor는 전역 심볼 레지스트리를 뒤져서 해당 심볼의 이름을 얻어냄. 검색 범위가 전역 심볼 레지스트리이기 때문에 전역 심볼이 아닌 심볼에는 사용할 수 없다. 전역 심볼이 아닌 인자가 넘어오면 Symbol.keyfor는 undefinend를 반환

  • 전역 심볼이 아닌 모든 심볼은 description프로퍼티가 있습니다. 일반 심볼에서 이름을 얻고 싶으면 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

시스템 심볼

  • 시스템 심볼은 자바스크립트 내부에서 사용되는 심볼 시스템 심볼을 활용하면 객체를 미세 조정

  • 명세서 내의 표, 잘 알려진 심볼에서 어떤 시스템 심볼이 있는지 살펴보세요

    • Symbol.hasInstance
    • Symbol.isConcatSpreadable
    • Symbol.iterator
    • Symbol.toPrimitive
    • 기타 등등
  • 객체가 어떻게 원시형으로 변환되는지 알기 위해선 Symbol.toprimitive에 대해 알아야 하는데, 자세한 내용은 곧 다루도록 하겠습니다.

  • 시스템 심볼 각각에 대한 내용은 연관되는 자바스크립트 기능을 학습


위 내용은 javascript.info 사이트에서 공부한 내용 정리
자세한 내용은 아래링크를 참고하세요
https://ko.javascript.info/symbol

profile
개발 옆차기

0개의 댓글