이번엔 Symbol에 대한 이야기를 할건데, 이게 진짜 난 도저히 엇다써야할지 감이 안 잡혀서 이해가 좀 힘들었다. 그냥 아무리 생각해도 ES6로 넘어오면서 언어 자체에 들어가있는 built-in 기능들을 위한 타입이지 않나? 정도 밖엔 감을 못잡았는데, 대충 정리해보면 그래도 JS 개발자가 조금씩 사용할 수 있는 것들이 존재하긴한다. 또한, 우리가 당연하게 사용하고 있던 것들 역시 Symbol로 정의 되어있기 때문에 알고 있으면 JS에 대한 깊은 이해에도 도움이 될 것으로 생각한다.
1. Symbol이란?
Symbol은 ES6부터 JavaScript에 추가된 타입으로, 좀 특이한 녀석이다. 사용의 목적은 Property들의 충돌을 방지하기 위해 고유한 Property를 만드는 용도로 사용된다. 이런 식으로 설명하고 있는데, 이런 이해도 안되는 어려운 말은 갖다 치워두고, 쉽게 한번 설명 좀 해보자.
내가 이해한 수준으로 설명해보면 Property를 그냥 딱 변경없이 정해놓고 사용해두고 싶은 그런게 있는데, 이럴 경우에 여기저기서 막 값이 바뀌는 그런 케이스를 방지하고 싶다. 이런 느낌이었는데, 예를 들면 진짜 딱 이런거임.
앞서 Prototype에 대한 이야기를 했는데, Prototype chain을 끝까지 타고 따라가 보면 그 종점에는 Object가 있다고 얘기를 헀었다.
(링크 달아두겠음)
2023.07.13 - [Dev/JavaScript] - [JavaScript] ProtoType (2)
내가 개발을 하면서 이 Object Prototype에 메서드 추가하고 이런 식으로 막 커스텀을 하고 싶다고 치자. 모든 객체가 사용할 수 있게끔 말이다. 근데 그 이름을 일반적인 Property 이름 정하듯이 그냥 막 때려버리면, 아마 분명 Object ProtoType 상속하는 다른 객체들이 동일한 이름의 Property를 가졌을 때 혼란이 있을 수도 있다. 라고 생각했다.
그래서 "아싸리 걍 생성할때마다 고유하면 아무런 걱정없이 쓸 수 있지 않아?" 라는 아이디어로 나온게 이거라고 난 이해했음.
2. Symbol 사용법
1) 기본 Symbol 사용법
사용법은 진짜 뭐 별거 없는데, 생성하고 이게 뭔 심볼인지 Description만 넣어주면 되는거임.
코드로 한번 보자.
const sym1 = Symbol('mySymbol')
const sym2 = Symbol('mySymbol')
const sym3 = Symbol('mySymbol')
const sym4 = Symbol('mySymbol')
이렇게 Symbol을 만들 수 있는데, 아니 저거 생성자 함수랑 비슷하게 생겼는디? 라고 얘기 할 수도 있지만 Symbol은 new 같은거 안키운다.
설명하자면 내용이 좀 많긴한데 최대한 간단하게 얘기해보자. 생각해보면 string, number, boolean 이런 애들은 new를 통한 생성이 가능한데, 왜 symbol은 안될까?
내가 단순히 생각했을 때는 well known symbol 때문인 것 같다. es2015좀 뜯어보면 symbol constructor가 두개가 있는데, wellknown symbol constructor가 있고, 그냥 constructor가 있음. 근데 wellknown은 우리가 흔히 사용하고 있는 JavaScript 기능들 예를 들면 막 hasInstance, replace, match 이런거 들어가있다. 이런거 때문에 Wrapper 객체를 생성할 수가 없는게 아닌가... 라는 추측정도 하고 있음. well known symbol은 밑에서도 설명하도록 하겠다.
2) 전역 심볼 레지스트리에 등록하기
이게 뭔 어려운 소린가 싶을텐데, 그냥 말그대로 전역에 갖다가 등록해두고, 어디서든 갖다 쓸 수 있으면 좋겠어서 존재하는거임. Symbol constructor가 기본 symbol을 생성할때는 그냥 description을 받는데 (생략가능함.), 이 전역 심볼 레지스트리에 등록하는 경우에는 찾을 수 있는 단서가 되는 key 값을 받는다. 이것도 코드로 한번 보자.
const sym = Symbol.for('key')
이 .for()를 통해서 전역에 등록하게 된다.
당연히 거꾸로 하는거도 있다. symbol을 넘겨주고 키를 가져올 수도 있음.
const key = Symbol.keyFor(sym)
이렇게 말이다.
3. Symbol 사용 용도
제일 중요한게 이 엇다쓰느냐 인데, 근데 감이 안잡혀버림. 공식 문서에서 적어둔 내용으로 내가 이해한 용도를 한번 써보겠다.
1) 캡슐화 (property 은닉)
캡슐화가 뭐냐는 얘기가 나올 것 같긴한데, 진짜 캡슐 생각하면 된다. 캡슐 뚜껑 딱 닫아두면 내용물 안 보이고, 그 안에 들어있는게 외부의 영향 없이 독립적이다. 이렇게 하고자 하는 것이 캡슐화임.
Java로 개발하면 맨날 이렇게 해서, Java가 예를 들기 쉬운데 클래스 만들어 놓고 모든 변수 private으로 만들어둔 다음에 getter, setter를 통해서만 저 변수에 접근 가능하도록 하는게 이 캡슐화의 일환이다.
제일 무난하게 쓸 수 있는게 이게 아닐까 싶다. symbol을 만들어 property로 써준 경우에는 Object.keys 나 for~in 이런걸로 확인해볼 수가 없다. 그래서 이런 속성이 있다는 사실을 숨길 수가 있다.
하지만 Object.getOwnPropertySymbols() 이거쓰면 다 볼 수 있음.
2) 표준 Built-in Object 확장
앞의 서론에서 말한 Prototype에 메서드 추가하고 이런거 할 때 쓸 수 있단 뜻이다. 모든 프로그램에 영향을 끼칠 수 있는 요소들의 경우 당연히 그 property들이 고유할 수록 안정성을 보장할 수가 있다. 그렇기 때문에 Symbol을 통해서 Property를 추가해주면 무조건 고유하기 때문에 아주 아름답게 걱정없이 확장이 가능하다!
4. Well-Known-Symbol
Well-Known-Symbol은 간단하게 말하면 원래 JS안에 들어있는 Symbol들을 얘기하는데, 앞에서 얘기한 것 처럼 hasInstance, match 이런 애들이랑 검색하면 매번 예시로 나오는 iterator도 동일한 느낌으로 난 받아들였다. JS에 존재하는 객체들에게 이런 Property들을 지정해두고 사용할 수 있게끔 만들어둔 것들이 이 Well-Known-Symbol에 해당한다.
'Dev > JavaScript' 카테고리의 다른 글
[JavaScript] BigInt (0) | 2023.07.25 |
---|---|
[JavaScript] iterable / iterator (0) | 2023.07.17 |
[JavaScript] Wrapper Object (0) | 2023.07.13 |
[JavaScript] ProtoType (2) (0) | 2023.07.13 |
[JavaScript] ProtoType (1) (0) | 2023.07.05 |