미션을 하던 중에 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
를 사용하면 된다.
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
에서 보면, NAME
과 NAME2
는 똑같이 '이름'
이지만 Symbol
타입이기 때문에 한 객체 안에서 같은 프로퍼티 키를 사용할 수도 있다. (이렇게 실제로 사용하는 예가 있는지는 잘 모르겠다.
라이브러리에서 사용자가 접근하거나 변경해서는 안 되는 프로퍼티에 쓴다고는 하는데 라이브러리를 써본 적도 없고 만들어본 적은 더더욱 없어서 실제로 어떻게 쓰이는지 잘 와닿지는 않지만 뭔 느낌인지는 알겠다. ㅎㅎㅎ 😎
도서 <모던 자바스크립트 Deep Dive: 자바스크립트의 기본 개념과 동작 원리>
모던 자바스크립트 튜토리얼 - 심볼형
인프런 채널 영상