javascript에 타입중 하나인 Symbol은 특수하게 작성되는 데이터값을 생성할 수 있는 생성자 함수이다.
기본적으로 웹 브라우저가 실행되면서 전역객체가 만들어질 때, 빌트인 생성자 함수로 제공되는 객체이다.
Symbol을 대표적으로 활용할만한 상황은 enum이다.
예를들어, redux에서 액션 타입을 설정할 때, 일일이 변수로 const ADD = "ADD" 와 같이 등록하기보다, 객체형태로 모아서 enum형태를 만들어 주어 key만을 필요로하게 만드는 것은 유용한 방법이 될 수 있다.
Symbol을 통해 만들어진 값은 메모리에 저장될 때 일반적으로 알아차릴 수 없는 특수한 심볼 값으로 형성되어 저장되기 때문에 오로지 그 데이터가 저장되어 있는 메모리 공간을 가리키는 식별자로만 접근할 수가 있다.
위와같은 이유는, Symbol의 인자로 전달되는 값은 오로지 해당 심볼을 설명하는 용도로 쓰일 뿐이기때문에 동일한 인자로 전달되어 만들어진 심볼은 서로 다른 값이다
{} !== {} 이 참인 것과 이유가 같다. 메모리 공간 입장에선 둘 다 서로다른 객체 레퍼런스가 메모리에 저장되어 있는 것일 뿐이다.
또한 Symbol은 프로퍼티의 descriptor 안의 정의에서 enumerable이 false이기 때문에, for in이나 Object.keys에 의해 발견되지 않는다
JSON으로도 찾아지지 않는다.
const ob = {
[Symbol("a")]: 10,
[Symbol("b")]: 20,
};
Object.getOwnPropertySymbols(ob);
// [Symbol(a), Symbol(b)]
Object.keys(ob);
// []
for (var i in ob) {
console.log(i);
}
// 반환값 없음
JSON.stringify(ob);
// "{}"
참고로, Symbol을 전역적으로 관리하여 중복되는 심볼이 없도록 만들고 싶다면, Symbol.for()을 통해 만들면 된다.
해당 방식으로 심볼을 만들 경우, 이 심볼들은 특수한 전역 심볼 테이블에 의해 관리가 되며 인자로 들어가는 내용이 key가 되어 등록된다.
즉, 동일한 형식으로 만들어지는 키의 심볼은 무시된다.
만약, React에서 제공하는 jsx를 생성하는 메서드 React.createElement를 호출하면, 특수한 jsx 객체를 만든다.
jsx는 javascript 안에 xml 문법이 들어가 있는 형태를 뜻한다.
const jsxMaker = React.createElement(
"div",
{ prop1 : "yes this is prop" },
"this is children"
)
위와 같이 만들 경우, react가 제공하는 특수한 jsx 객체를 확인할 수 있다.
위에서 보면 특수한 프로퍼티 $$typeof로 Symbol(react.element) 가 있는 것을 확인할 수 있다.
(참고로, 해당 심볼은 Symbol.for("react.element") 로 만들어져있다. 즉, 글로벌한 심볼테이블로 react상에서 관리가 되는 값이다);
리엑트가 만들어지고 있는 과정에서, 리엑트 팀이 봉착한 가장 큰 문제점이 xss를 어떻게 효과적으로 컴포넌트별로 막을 것인가에 대한 문제였다.
위의 객체에서도 확인할 수 있는것처럼, 만들어지는 요소의 형태는 아래와 같을 것이다.
<div prop1="this is prop">this is children</div>
즉, div 태그의 자식으로 텍스트를 가져올 수 있다. 이말인 즉슨, 자식에 악의적인 스크립트가 담겨있으면 XSS공격에 취약해진다.
물론, html5와 같은 경우 일반 text에 스크립트 태그가 들어가 있는 것은 자동적으로 방어하도록 되어있기 때문에 괜찮아졌지만 문제는 서버에서 오류가 생겨서 일반 텍스트가 들어와야 할 장소에 JSON가 들어오게 되는 것과 같은 문제가 생겼을 때이다.
예를들어
<p>
{message.text} <-- text가 JSON일 경우, 에러의 발생 (서버결함으로)
</p>
이런 경우를 막기 위해, 리엑트에는 이런 경우를 막기 위하여 $$typeof로 심볼값을 모든 jsx 객체에 설정하도록 하게 만들었다.
JSON의 특성상, Symbol값은 넣을 수가 없다. 즉, 만약 message.text에 JSON이 들어가 있다 하더라도,
p 태그의 자식의 입장에서 내부로 들어오는 자식 jsx객체로 보이는 (?) 녀석에 Symbol("react.element") 가 존재하지 않으므로 element의 생성을 거부한다.