Frontend/JS.info 정리

객체: 기본 - 심볼 ( Symbol )

Creative_Lee 2021. 12. 27. 20:51

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

 

Symbol ?

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

let test = Symbol('테스트 심볼')

console.log(test) // Symbol(테스트 심볼)

심볼은 Symbol() 로 만들 수 있고,
괄호안에 '심볼 이름' 이라고 불리는 심볼의 대한 설명을 붙일 수 있습니다.

 

심볼은 유일성이 보장되는 자료형입니다.

때문에 심볼 설명이 동일한 여러 개의 심볼을 만들어도 각 심볼값은 다릅니다.

let test1 = Symbol('테스트 심볼')
let test2 = Symbol('테스트 심볼')


console.log(test1 == test2) // false
console.log(test1 === test2) // false

심볼값은 서로 다릅니다!!

 

심볼은 자동 형 변환이 안된다.

자바스크립트에서는 문자형으로의 암시적 형 변환이 비교적 자유롭게 일어납니다.

그렇기에 alert 함수가 거의 모든 값을 인자로 받을 수 있죠!

하지만 심볼값은 다른 자료형으로의 자동 형 변환이 되지 않습니다. 

아래 코드는 에러가 발생합니다.

let test1 = Symbol('테스트 심볼')

alert(test1)  // TypeError: Cannot convert a Symbol value to a string

문자열과 심볼은 근본이 다릅니다!

고로 우연히라도 서로의 타입으로 변환이 일어나서는 안됩니다.

자바스크립트에서는 언어 차원의 보호장치가 심볼형의 자동 형 변환을 막아줍니다.

 

 

심볼을 반드시 출력해야 한다면?

let test1 = Symbol('테스트 심볼')

alert(test1.toString())	// Symbol(테스트 심볼)

.toString() 메소드를 활용합니다.

 

심볼의 설명만 보고싶다면?

let test1 = Symbol('테스트 심볼')

console.log(test1.description)  // 테스트 심볼

symbol.description 프로퍼티를 활용합니다.

 

 

symbol 로 숨김 프로퍼티 만들기

숨김 프로퍼티는 외부 코드에서 접근이 불가능하고 값의 쓰기가 불가능합니다!

심볼로 한번 만들어 봅시다!

 

 

1. 서드파티 코드에서 가져온 user 객체가 여러 개 있고,

   이 객체를 활용해 어떤 작업을 해야 한다고 가정합시다.

let user = {
  name: 'Lee'
}

 

2. user 객체는 다른 파일의 코드에서 가져왔기 때문에 함부로 프로퍼티를 추가할 수 없습니다.

   이때 스크립트에서 심볼을 사용해서 만든 id라는 식별자는 user 객체를 가져온 코드에서 접근할 수 없기 때문에

   가져온 코드에 변형없이 user 객체로 작업이 가능합니다.

let user = {
  name: 'Lee'
}

let id = Symbol('유저 id')

user[id] = 1  // symbole 이름은 문자열이기 때문에 대괄호 표기법을 사용합니다.

console.log(user) // {name: 'Lee', Symbol(유저 id): 1}
console.log(user[id]) // 1 

유저id라는 symbol 값이 1 인 user 객체 입니다.

   

3. 여기서 갑자기 또 다른 제 3의 스크립트에서 user객체를 사용해야 한다면?

   그저 symbol 을 만들어 주면 됩니다. 

let user = {
  name: 'Kim'
}

let id = Symbol('유저 id')

user[id] = 12

console.log(user) // {name: 'Lee', Symbol(유저 id): 12}
console.log(user[id]) // 12

  심볼의 유일성 덕분에 2번에서 만든 symbol 과 3번에서 만든 symbol 은 서로 다릅니다.

  고로 각 파일에서 만든 식별자는 서로 충돌하지 않습니다.

  만약 심볼 대신 문자열을 사용해 프로퍼티 키를 만들었다면

  당연하게도 각 파일의 user.id 는 서로 충돌하여 덮어쓰기 되면서 난리가 날겁니다!!!!

 

 

symbol은 for...in문 에서 제외됩니다!

키가 심볼인 프로퍼티는 for..in 반목문의 대상에서 제외됩니다!

let pw = Symbol('pw')

let user = {
  name: 'Kim',
  id : 'go heaven',
  [pw] : 1234
}

for(let key in user) {
  console.log(`${key} : ${user[key]}`)		// name : Kim
}						// id : go heaven

심볼로 만든 pw는 출력되지 않았습니다.

 

symbol은 Object.keys() 에도 제외됩니다!!

console.log(Object.keys(user)) // ['name', 'id']

 이러한 원칙 덕분에 외부 스크립트, 라이브러리에서는 심볼형 키를 가진 프로퍼티에는 접근이 불가능 합니다!

 

 

symbol은 Object.assign() 에서는 복사됩니다!! 

Object.assign을 사용해 객체를 복사할 땐 심볼을 포함한 모든 프로퍼티가 복사됩니다!

let pw = Symbol('pw')

let user = {
  name: 'Kim',
  id : 'go heaven',
  [pw] : 1234
}

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

console.log(clone)  // {name: 'Kim', id: 'go heaven', Symbol(pw): 1234}

 

 

전역 Symbol

위의 예시와는 다르게

이름이 같은 심볼이 같은 개체를 가리키길 원하는 경우에 전역 symbol을 활용할 수 있습니다!

 

전역 심볼 레지스트리는 이런 경우를 위해 만들어졌습니다.

전역 심볼 레지스트리 안에 전역 심볼을 생성하면 해당 심볼 이름으로 여러 곳에서 접근할 수 있습니다.

 

전역 심볼은 Symbol.for(' 심볼이름 ') 을 통해 생성하고 읽을 수 있습니다.

심볼이름이 없으면 생성하고 있으면 읽어 옵니다!

let pw = Symbol.for('pw') // 전역 심볼이 생성됩니다.
let pwpw = Symbol.for('pw') // 위에서 생성된 전역 심볼을 리턴합니다!

console.log(pw == pwpw) // true
console.log(pw === pwpw) // true

 

Symbol.keyFor( )

Symbol.keyFor( 심볼 ) 을 활용하면 심볼 이름을 얻을 수 있습니다.

Symbol.for( ) 의 반대 개념이라고 이해합시다!

 

위 두 메서드는 전역 심볼에만 사용 가능합니다.

let pw = Symbol.for('pw 인데용?') 
let pwpw = Symbol.for('pw 입니다.') 

console.log(Symbol.keyFor(pw)) //pw 인데용?
console.log(Symbol.keyFor(pwpw)) //pw 입니다.

 

 

 

 

 

기본이 중요하다.