본문 바로가기

Tech/[Lang] JS & TS

유일성을 보장하는 자료형, 심볼형

Hi, There!
안녕하세요, 바오밥입니다.


목차

  1. 개요
  2. 본문
  3. Reference

개요

유일성을 보장하는 자료형인 심볼형에 대해서 정리하였습니다.

혼자 개발할 때는 자주 사용되지 않으며, 협업 시에 이점이 있는 자료형입니다.


본문

심볼 (Symbol)

심볼형 선언

심볼형은 유일한 식별자를 만들 때 사용합니다.

const a = Symbol()
console.log(typeof(a)) // symbol

심볼형으로 만든 변수들은 값이 같아도 각자 다른 식별자를 나타냅니다.

따라서 동등 연산자와 일치 연산자로 비교 하였을 때 모두 false 값을 반환합니다.

const a = Symbol()
const b = Symbol()

console.log(a==b) // false
console.log(a===b) // false

 

객체 프로퍼티 키의 암시적 형 변환

객체 프로퍼티 키를 숫자형 또는 불린형으로 선언 했어도 문자형으로 반환됩니다.

const key = {
  1: "1입니다.",
  false: "거짓"
}

console.log(Object.keys(key)) **// ["1", "false"]**

다만, 객체 프로퍼티 키를 심볼형으로 선언한 경우 암시적 형 변환이 일어나지 않습니다.

또한 심볼형으로 선언한 프로퍼티 키는 히든 프로퍼티로 동작됩니다.

숨김 속성 (Hidden Property)
숨김 속성인 키는 외부 코드에서 접근이 불가능하고 값도 덮어쓸 수 없습니다.

**const id = Symbol('id');**
const key = {
  1: "1입니다.",
  false: "거짓",
  **[id]: "userId"**
}

console.log(Object.keys(key)) **// ["1", "false"], 심볼형은 출력되지 않습니다.
console.log(key[id]) // userId, 심볼형으로 직접 접근해야 출력됩니다.**

 

객체 프로퍼티 키를 심볼형으로 사용하는 경우

객체 프로퍼티 키를 문자형 대신 심볼형으로 사용하는 경우는 여러 사람이 한 코드를 사용할 때 주로 발생합니다.

서드파티 코드에서 불러온 객체를 예로 들겠습니다. 서드파티 코드 객체는 자신 말고도 다른 개발자들이 사용하고 있기 때문에 함부로 새로운 프로퍼티를 추가할 수 없습니다.

만약 함부로 추가할 경우 의도치 않은 결과 값을 불러올 수 있기 때문입니다.

이때, 심볼형을 사용하면 다른 개발자들이 사용하고 있는 서드파티 코드에서 자신의 코드로 접근할 수 없게 되므로 자신만의 프로퍼티를 추가할 수 있게 됩니다.

 

객체 프로퍼티 키를 심볼형으로 사용하지 않고 문자형으로 추가한 경우

// A 개발자의 원본 코드
let user = {
  name: "mike"
}
user.id = "identity : A"

// B 개발자의 코드
user.id = "identity : B"

console.log(user.id) // "identity : B", 원본 코드의 identity : A 값이 덮어 씌워집니다.

 

객체 프로퍼티 키를 심볼형으로 추가한 경우

// A 개발자의 원본 코드
let user = {
  name: "mike"
}
user.id = "identity : A"

// B 개발자의 코드
let id = Symbol("id");
user[id] = "identity : B"

console.log(user[id]) // "identity : B", 자신만의 프로퍼티 값이 할당되었습니다.
console.log(user.id) // "identity : A", 원본 프로퍼티 값은 여전히 유효합니다.

 

심볼형과 객체 메서드

심볼형으로 선언된 프로퍼티는 히든 프로퍼티로서 작동하기 때문에 객체 메서드에 영향을 받지 않습니다.

따라서 [] 를 이용하여 히든 프로퍼티에 직접 접근해야 합니다.

let user = {
  name: "jhkim"
}

let id = Symbol('id')

user[id] = 1

console.log(Object.keys(user)) // ["name"]
console.log(Object.values(user)) // ["jhkim"]
console.log(Object.entries(user)) // [ ["name","jhkim"] ]
console.log(user[id]) // 1

 

객체 복제 메서드인 Object.assign()는 히든 프로퍼티를 포함하여 복제합니다.

이는 설계의 의도와 모순된 내용이지만 편의상 의도적으로 배제하지 않은 것입니다.

let user = {
  name: "jhkim"
}

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

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

console.log(clone[id]) // 1, user의 히든 프로퍼티가 출력됩니다.

 

전역 심볼형의 필요성

개발자 A는 서드파티 객체의 프로퍼티를 수정하여 자신의 기능을 추가하였습니다.

이후 기능을 확장하게 되었고 어플리케이션 곳곳에서 공통된 심볼 개체를 가리켜야 하는 상황이 발생했습니다.

그러나 심볼의 유일성 때문에 의도치 않은 결과 값이 발생하게 됩니다.

이런 상황은 전역 심볼을 사용하여 해결할 수 있습니다.

전역 심볼을 통해 심볼형을 생성할 경우 전역 심볼 레지스트리에 저장되고 해당 심볼에 접근하는 경우 이름이 같은 심볼을 반환 해 줍니다.

 

전역 심볼형 선언

전역 심볼형의 경우 Symbol.for() 메서드를 통해 생성할 수 있습니다.

전역 심볼형의 이름이 같은 경우 동등 연산자와 일치 연산자에서 모두 true 를 반환합니다.

이는 전역 심볼형이 같은 개체를 가리키고 있다는 것을 의미하기도 합니다.

// A 개발자의 기능1.js
const id = Symbol.for('id')

// A 개발자의 기능2.js
const idAgain = Symbol.for('id')

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

 

이미 선언되어 있는 전역 심볼형 찾기

전역 심볼형이 이미 선언되어 있는 지 확인하고 싶을 때는 Symbol.keyFor()를 사용합니다.

const id = Symbol.for('id')
console.log(Symbol.keyFor(id)) // 'id', 전역 심볼 레지스트리에 저장돼 있는 이름을 반환합니다.

 

전역 심볼 레지스트리에 있는 값을 반환하는 것이기 때문에 일반 심볼형의 경우 이름이 반환되지 않습니다.

const id = Symbol('id')
console.log(Symbol.keyFor(id)) // undefined

 

이미 선언되어 있는 일반 심볼형 찾기

일반 심볼형의 이름을 반환해야 하는 경우 description 프로퍼티를 사용합니다.

const localId = Symbol('id')
console.log(localId.description) // "id", 심볼형의 이름을 반환합니다.

 

심볼형이 많이 사용되는 경우

  • 외부 스크립트나 라이브러리와 같은 서드파티 코드에 '속한' 객체에 새로운 프로퍼티를 추가할 때 사용합니다.
  • 프로퍼티의 키가 심볼형인 경우 서드파티 코드에서 접근하지 못하기 때문에 의도치 않은 프로퍼티 수정을 예방할 수 있습니다.
  • 프로퍼티의 키가 심볼형인 경우 for .. in 반복문에서 배제됩니다.

 


Reference

 

 

 

'Tech > [Lang] JS & TS' 카테고리의 다른 글

문자열 메서드  (0) 2021.09.03
숫자형과 수학 메서드  (0) 2021.09.02
객체 메서드와 계산된 프로퍼티  (0) 2021.08.30
생성자 함수  (0) 2021.08.27
호이스팅과 TDZ  (0) 2021.08.26