JS) Symbol

kangdari·2020년 4월 1일
1

기본형 / 참조형 변수

기본형(Primitive Value)
주소 값에 값이 그대로 들어옴.

Number String Boolean null undefined Symbol

참조형(Reference Value)
기본 주소 값 외에 별개의 데이터가 존재

Object Array function Map Set WeakMap WeakSet

Symbol

  • Primitive Value => 유일무이한 고유한 존재
  • 비공개 멤버(private)에 대한 needs에 탄생
  • 기본적인 열거 대상에서 제외 ( for문, fon in문 )
  • 형 변환 불가능
  • 생성

Symbol([string]): 문자열이 아닌 타입은 자동으로 toString 적용

new 연산자를 사용하지 않음

const sb1 = Symbol()
const sb2 = Symbol()

console.log(sb1, sb2) // Symbol() Symbol()
console.log(sb1 == sb2) // false
console.log(sb1 === sb2) // false
const sb1 = Symbol('symbol')
const sb2 = Symbol('symbol')

console.log(sb1, sb2) // Symbol(symbol) Symbol(symbol)
console.log(sb1 === sb2) // false
  • 객체 프로퍼티의 키로 활용

Symbol로 선언된 프로퍼티는 열거 대상이 아닙니다.

외부에서 Symbol로 선언된 프로퍼티에는 접근이 불가능. >> 은닉화
객체 내부에서 식별자로만 사용된다.

const NAME = Symbol('이름')
const GENDER = Symbol('성별')
const kang = {
    [NAME]: 'kang',
    [GENDER]: 'male',
    age: 27,
}
const kim = {
    [NAME]: 'kim',
    [GENDER]: 'female',
    age: 24
}

console.log(kang, kim)
// { age: 27, [Symbol(이름)]: 'kang', [Symbol(성별)]: 'male' }
// { age: 24, [Symbol(이름)]: 'kim', [Symbol(성별)]: 'female' }
  • 프로퍼티 키로 할당한 심볼 접근(탐색)
 Reflect.ownKeys(kang).forEach(i => {
    console.log(i, kang[i])
    	// age 27
	// Symbol(이름) kang
	// Symbol(성별) male
})

private member 만들기

캡슐화를 위해 ... private 흉내만 내는 정도

const obj = ( () => {
    // 내부 함수에서 Symbol 선언한 값은 블록 스코프안에서만 유효 
    const _privateMember1 = Symbol('private1')
    const _privateMember2 = Symbol('private2')
    return {
        [_privateMember1]: '외부에서 보이긴 하는데 접근할 방법이 애매해...',
        [_privateMember2]: 10,
        publicMember1: 20,
        publicMember2: 30
    }
})() // 즉시 실행 함수

console.log(obj)
console.log(obj[Symbol('private1')]) // undefined
console.log(obj[_privateMember1]) // ReferenceError: _privateMember1 is not defined

obj[Symbol('private1')]: 새로운 Symbol을 만든 것이므로 접근이 불가능
Symbol('private1') === Symbol('private1') // false

obj[_privateMember1]: 외부에서 접근 가능한 _privateMember1 변수가 없으므로 오류

  • 접근 시도
    for in문 Objeck.keys()로 접근 시 Symbol로 선언된 프로퍼티는 접근
for( const prop in obj){
    console.log(prop, obj[prop])
    // publicMember1 20
    // publicMember2 30
}

Object.keys(obj).forEach(item => {
    console.log(item, obj[item])
    // publicMember1 20
    // publicMember2 30
})

Symbol에 접근은 가능하나 정상적인 접근법이 아니다.

Object.getOwnPropertySymbols(obj).forEach(i =>{
    console.log(i, obj[i]) // Symbol(private1) 외부에서 보이긴 하는데 접근할 방법이 애매해...
                           // Symbol(private2) 10
})

Reflect.ownKeys(obj).forEach(i => {
    console.log(i, obj[i]) //publicMember1 20
                           // publicMember2 30
                           // Symbol(private1) 외부에서 보이긴 하는데 접근할 방법이 애매해...
                           // Symbol(private2) 10
})

Symbol.for(str) - 공유 심볼

public memeber: 전역 공간에서 공유되는 심볼.

  • 스코프에 갇히지 않는다.
  • 한번 선언된 것을 다시 선언 시 최초 선언한 값을 접근된다.
const a = Symbol.for('public')
const b = Symbol.for('public')
a === b // true

Symbol로 선언했을 때에는 항상 새로운 값이 생성되므로 a===b는 false였습니다.
하지만 Symbol.for()로 선언하는 경우는 다릅니다.
Symbol.for('public'): public이라는 문자열이 처음 생성된 경우 메모리 공간에 그 값을 저장합니다. 이후 또 다시 public이라는 문자열로 생성 시 이미 저장해둔 값을 가져와 사용합니다. 즉, public 문자열을(메모리) 참조합니다.
그렇기 때문에 a===b는 true 입니다.


const obj = (() => {
    const COMMON1 = Symbol.for('public')
    return {
        [COMMON1]: '공유할 프로퍼티 값. 어디서든 접근 가능.'
    }
})();

obj[Symbol.for('public')] // "공유할 프로퍼티 값. 어디서든 접근 가능."

public 문자열로 Symbol.for를 생성했으므로 public이라는 문자열만 알고 있으면 어디서든 접근이 가능합니다.


  • Symbol.keyFor()
const COMMON1 = Symbol.for('public')
const COMMON2 = Symbol.for('public')
const UNCOMMON = Symbol('비공유')

const commonSymbolKey1 = Symbol.keyFor(COMMON1) // public
const commonSymbolKey2 = Symbol.keyFor(COMMON2) // public
const commonSymbolKey3 = Symbol.keyFor(UNCOMMON) // undefined

Symbol.for()를 사용하여 만든 변수에 대해서는 Symbol.keyFor()을 사용할 수 있다.
선언할 때 사용한 문자열을 출력해줌.


0개의 댓글