JS | Symbol 타입 알아보기

Autumn·2021년 1월 11일
0

JavaScript

목록 보기
11/18
post-thumbnail

미션을 하던 중에 Symbol 타입을 써보면 어떨까 하는 생각이 들어서 공부하다가 인프런 채널에 올라온 이 영상을 봤다. 영상 4:30 쯤에 '변수에 접근하기 위해서 대괄호 표기법을 쓴 거, 아시죠?' 라고 하시는데... 전.. 모르는데요..? 😭 그래서 우선 저 문법이 무엇인지 찾아보고 Symbol 타입에 대해서도 더 공부해보기로 결심 🤓


객체 리터럴 '계산된 프로퍼티 이름'

ES6에서는 객체 리터럴 내부에서 계산된 프로퍼티 이름으로 프로퍼티 키를 동적으로 생성할 수 있게 되었다. (명칭만 보고는 뭔소린지 잘 와닿지가 않았다.)

C++나 자바와 같은 클래스 기반 객체지향 언어는 객체를 생성할 때 클래스를 먼저 정의하고 인스턴스를 만들어야 하는데, 프로토타입 기반 객체지향 언어인 자바스크립트는 다양한 객체 생성 방법을 지원한다.

  • 객체 리터럴
  • Object 생성자 함수
  • 생성자 함수
  • Object.create 메서드
  • 클래스 (ES6)

이 중에서 가장 간편하게 쓸 수 있는 방법은 객체 리터럴이며, 객체 리터럴 방식으로 생성된 객체 또한 객체를 생성한 이후에 프로퍼티를 동적으로 추가할 수 있다. (참고 - 객체 리터럴 외의 객체 생성 방식은 모두 함수를 사용한 방식이다.) 문자열 또는 문자열로 평가할 수 있는 표현식을 사용해 프로퍼티 키를 동적으로 생성할 수 있는데, 이 경우에는 프로퍼티 키로 사용할 표현식(expression, '값'을 리턴하는 것)을 대괄호([])로 묶어야 한다. 이것이 바로 계산된 프로퍼티 이름이다.

// ES6
const prefix = 'prop';
let i = 0;

// 객체 리터럴 내부에서 계산된 프로퍼티 이름으로 프로퍼티 키 동적 생성
const obj = {
  [prefix]: i,
};

console.log(obj); // {prop: 0}

예제를 보니 말 뜻이 이해가 됐다. '계산된' 프로퍼티라는 것은 위 예제에서처럼 변수에 값을 할당해둔.. 이라고 이해하면 될 것 같다! key에다가 변수에 할당된 값을 넣고싶을 때! 변수를 대괄호에 넣기!!

예제 하나 더 보자.

const NAME = Symbol('이름')
const GENDER = Symbol('성별')
const iu = {
  [NAME]: '아이유',
  [GENDER]: 'female',
  age: 26
}
const suzi = {
  [NAME]: '수지',
  [GENDER]: 'female',
  age: 26
}
const jn = {
  [NAME]: '재남',
  [GENDER]: 'male',
  age: 30
}

console.log(iu, suzi, jn);
// {age: 26, Symbol(이름): "아이유", Symbol(성별): "female"}
// {age: 26, Symbol(이름): "수지", Symbol(성별): "female"}
// {age: 26, Symbol(이름): "재남", Symbol(성별): "male"}

Symbol은 열거 대상에서 제외되기 때문에, 객체의 고유한 식별자 이상의 의미를 가지지 않는다. Symbol을 프로퍼티 키로 사용할 때는 대괄호 표기법을 쓸 수밖에 없다. 객체의 프로퍼티 키에는 문자열만 쓸 수 있기 때문이다. (참고 - Map의 키에는 Symbol 사용 가능) 변수에 담지 않고 그냥 키에 [Symbol('a')] 이런 식으로 쓰면 value를 알아낼 수 있는 방법이 없다. 은닉화임을 떠나서 나조차도 못쓰게 되는 의미 없는 은닉화...!

Reflect.ownKeys(iu).forEach(k => {
  console.log(k, iu[k])
})
// age 26
// Symbol(이름) "아이유"
// Symbol(성별) "female"

Symbol 여부에 상관 없이 모든 값을 알아내려면 Reflect.ownKeys 를 사용하면 된다.


property key에 Symbol 사용하는 이유

const NAME = Symbol('이름');
const NAME2 = Symbol('이름');
const a = 'a';
const b = 'a';

const obj = {
  [NAME]: 'Autumn',
  [NAME2]: 'bbukku',
};
const obj2 = {
  [NAME]: 'Autumn',
  [a]: '아무거나',
  [b]: '아무거나2',
}

console.dir(obj);
console.dir(obj2);

console.log(obj[NAME] === obj2[NAME]); // true ⭐️
console.log(obj['이름']); // undefined

위에 있는 아이유, 수지 예제 코드처럼 프로퍼티 키에 Symbol을 사용했을 경우에 대해서 의문점이 생겼다. 내가 작성한 예제 코드에서 ⭐️ 부분을 보면 (당연히 같은 string이니까) 같다(true)고 나오는데, 그렇다면 객체의 고유한 식별자로써의 의미가 있나? 이런 생각이 들었다.

프로퍼티 키에 Symbol을 사용하는 것은 내가 오해했던 객체의 ID 같은 역할을 위한 것이 아니라, 사용자의 접근을 차단하거나 의도치 않은 프로퍼티 덮어쓰기를 방지하는 것에 목적이 있었다. 코드 마지막 줄에 '이름' 으로 접근이 안 되고, 같은 string을 담아둔 변수 a, b를 중복으로 프로퍼티에 넣어줬을 때는 나중에 넣은 아무거나2로 덮어쓰기가 된 것을 확인할 수 있다. 또한 obj에서 보면, NAMENAME2는 똑같이 '이름' 이지만 Symbol 타입이기 때문에 한 객체 안에서 같은 프로퍼티 키를 사용할 수도 있다. (이렇게 실제로 사용하는 예가 있는지는 잘 모르겠다.

라이브러리에서 사용자가 접근하거나 변경해서는 안 되는 프로퍼티에 쓴다고는 하는데 라이브러리를 써본 적도 없고 만들어본 적은 더더욱 없어서 실제로 어떻게 쓰이는지 잘 와닿지는 않지만 뭔 느낌인지는 알겠다. ㅎㅎㅎ 😎


참고자료

도서 <모던 자바스크립트 Deep Dive: 자바스크립트의 기본 개념과 동작 원리>
모던 자바스크립트 튜토리얼 - 심볼형
인프런 채널 영상

profile
한 발짝씩 나아가는 중 〰 🍁 / 자잘한 기록은 아래 🏠 아이콘에 연결된 노션 페이지에 남기고 있어요 😎

0개의 댓글