본문 바로가기
프로그래밍 개발/JS ES6+

Javascript ES6+ 심볼(Symbol)

by Jinseok Kim 2020. 12. 15.
반응형

 

 

심볼(Symbol)

 

 

  • primitive value => 유일무이하고 고유한 존재.
  • 비공개 멤버에 대한 needs에서 탄생.
  • 기본적인 열거대상에서 제외.
  • 암묵적 형변환 불가.

 

 

 

 

`Symbol([string])` : 문자열이 아닌 타입은 자동으로 toString 처리한다.

 

const sb1 = Symbol()
const sb2 = Symbol()
console.log(sb1,sb2)
console.log(sb1 === sb2)
//결과: 오류


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


const obj = {a:1}
const sb1 = Symbol(obj)
const sb2 = Symbol(obj)
console.log(sb1, sb2)
console.log(sb1 === sb2)
//결과:
//Symbol([object Object]) Symbol([object Object]) (자동으로 toString이 먹힌다.)
//false


const sb = Symbol(null)
console.log(typeof sb)
//결과:
//symbol

 

  • 위의 Symbol의 코드들 결과를 보면 Symbol의 인자로 같은 문자열이 들어간다 해도 비교 연산으로 확인하면 false가 뜬다. 즉 아무리 같은 문자를 품고있어도 Symbol은 자신 하나로서 유일무이하다라고 볼 수 있다. 
  • 또 Symbol 인자에 들어간 문자열이 아닌 타입은 자동으로 toString 처리한다는 성질 또한 확인 할 수 있다.
  • typeof로 타입은 확인 할 수는 있다.

 

 

 

 

 

객체 프로퍼티의 키로 활용

 

const NAME = Symbol('이름')
const GENDER = Symbol('성별')
const i = {
[NAME]: 'jinseok',
[GENDER]: 'male',
    age: 25        
}

const i2 = {
[NAME]: 'kim',
[GENDER]: 'male',
    age: 26          
}
const i3 = {
  [NAME]: 'jin',
  [GENDER]: 'male',
  age: 30
}

console.log(i, i2, i3)

//결과:
//{age: 25, Symbol(이름): "jinseok", Symbol(성별): "male"} {age: 26, Symbol(이름): "kim", Symbol(성별): "male"} {age: 30, Symbol(이름): "jin", Symbol(성별): "male"}

 

  • 위의 코드처럼 객체 프로퍼티 키로 활용할 수 있다.
  • Symbol의 성질로 인해 쉽게 상수로서 쓸 수 있게 되었다. 하나의 고유의 식별자로 사용하는 것이다. i, i2, i3 객체 안에서만 쓸 수 있는 고유의 식별자라고 말할 수 있다.

 

 

 

 

 

심볼 탐색

 

Object.getOwnPropertySymbols(i).forEach(k => {
  console.log(k, iu[k])
})

Reflect.ownKeys(i2).forEach(k => {
  console.log(k, iu[k])
})

 

  • 심볼을 탐색할 수 있는 것은 getOwnPropertySymbolsownKeys 메소드를 예로 들 수 있다. 다른 메소드 등등은 Symbol의 특성상 탐색할 수 없다.

 

 

 

 

 

 

 

private member 만들기

 

const obj = (() => {
  const _privateMember1 = Symbol('private1')
  const _privateMember2 = Symbol('private1')
  return {
    [_privateMember1]: '외부에서 보이긴 하는데 접근할 방법 X',
    [_privateMember2]: 10,
    publicMember1: 20,
    publicMember2: 30
  }
})() //즉시 실행 함수이다.
console.log(obj)
console.log(obj[Symbol('private1')])
console.log(obj[_privateMember1])

for (const prop in obj) {
  console.log(prop, obj[prop]) // 오류
}

Object.keys(obj).forEach(k => { // 오류
  console.log(k, obj[k])
})

Object.getOwnPropertyNames(obj).forEach(k => { // 오류
  console.log(k, obj[k])
})


// 아래 방법들로는 접근 가능하나 마땅치 않음
Object.getOwnPropertySymbols(obj).forEach(k => { 
  console.log(k, obj[k])
})

Reflect.ownKeys(obj).forEach(k => {
  console.log(k, obj[k])
})

 

  • Symbol로 만든 위의 코드의 private member Java 언어에서의 캡슐화같은 외부에서 절대 건들 수 없게 만드는 코드를 자바스크립트에서 흉내냈다고 말할 수 있다.
  • 실수로 혹은 기억이 안나서, 협업시 실수로 수정할 수 있는 여지를 방지하기 위하여 저렇게 캡슐화를 해준 것이다.

 

 

 

 

 

 

 

 

Symbol.for

 

 

 public member이며 전역공간에서 공유되는 심볼이다. 그냥 Symbol과 전혀 반대라고 보면 된다.

 

 

const COMMON1 = Symbol.for('공유심볼')
const obj = {
    [COMMON1]: '공유 프로퍼티 키값, 어디서든 접근 가능'
    
}
console.log(obj[COMMON1]) // 결과: 공유심볼

const COMMON2 = Symbol.for('공유심볼')
console.log(obj[COMMON2]) // 결과: 공유심볼


console.log(COMMON1 === COMMON2) // 결과: true

const UNCOMMON = Symbol('비공유심볼')
const commomSymbolkey1 = Symbol.keyFor(COMMON1)
const commomSymbolkey2 = Symbol.keyFor(COMMON2)
const commomSymbolkey2 = Symbol.keyFor(UNCOMMON)

 

const obj = (() => {
    const COMMON1 = Symbol.for('공유심볼')
    return {
        [COMMON1]: '공유할 프로퍼티 키값. 어디서든 접근 가능'
    }
})() //즉시 실행 함수
const COMMON2 = Symbol.for('공유심볼')
console.log(obj[COMMON2])

//결과:
//공유할 프로퍼티 키값. 어디서든 접근 가능

 

  • Symbol.for은 그냥 Symbol과 다르게 전역공간에서 공유될 수가 있다.
  • 위의 코드를 보면 Symbol.for이 공용으로 쓰여 어느 변수에 선언되든 그냥 Symbol과 다르게 똑같은 값 결과를 보여주는 것을 확인 할 수있다.

 

 

 

 

 

 

표준 Symbol

 

 

 

 

const arr = [4, 5, 6]
arr[Symbol.isConcatSpreadable] = true
console.log([1, 2, 3].concat(arr))

arr[Symbol.isConcatSpreadable] = false
console.log([1, 2, 3].concat(arr))

//결과:
//[1, 2, 3, 4, 5, 6]
//[1, 2, 3, Array(3)]

 

  • Symbol.isConcatSpreadable: array의 `concat` 메소드에 인자로 넘길 때 이를 flatten(접을지)할지 여부를 가리키는 boolean값 (default: true)
  • Symbol.hasInstance: instance instanceof constructor` 명령은 내부적으로 `constructor[Symbol.hasInstance](instance)` 으로 동작. 

 

 

 

 

class Person {
    constructor (name) { this.name = name}
}
const jin = new Person('jinseok')
console.log(jin.toString())

Person.prototype[Symbol.toStringTag] = 'PERSON'
console.log(jin.toString())

//결과
//[object Object]
//[object PERSON]

 

  • Symbol.toStringTag: `Object.prototype.toString`이 호출되었을 때 어떤 명칭을 반환할 지를 지정 가능.

 

 

 

 

 

 

 

표준 심볼의 다양한 활용

 

const str = '이 _ 문자열을 _ 이렇게 _ 나누어라.'
String.prototype[Symbol.split] = function (string) {
  let result = ''
  let residue = string
  let index = 0
  do {
    index = residue.indexOf(this)
    if(index <= -1) {
      break
    }
    result += residue.substr(0, index) + '/'
    residue = residue.substr(index + this.length)
  } while (true)
  result += residue
  return result
}
console.log(str.split(' _ '))

// 결과:
// 이/문자열을/이렇게/나누어라.

 

  • Symbol.split: 문자열을 나누는 조건 설정

 

 

 

 

 

 

 

반응형

'프로그래밍 개발 > JS ES6+' 카테고리의 다른 글

Javascript ES6+ Map  (0) 2020.12.16
Javascript ES6+ Set  (0) 2020.12.16
Javascript ES6+ Destructuring assignment  (0) 2020.12.14
Javascript ES6+ Function 함수  (0) 2020.12.14
Javascript ES6+ Arrow Function  (0) 2020.12.11

댓글