우당탕탕 개발일기

모던 자바스크립트 33. 7번째 데이터 타입 Symbol 본문

What I Learned/JavsScript

모던 자바스크립트 33. 7번째 데이터 타입 Symbol

rilee 2024. 7. 10. 14:17
728x90

심벌Symbol은 ES6부터 도입된 7번째 데이터 타입이다. 

변경 불가능한 원시 타입의 값이며 다른 값과 중복되지 않는 유일무이한 값이다.

따라서 이름 충돌 위험이 없는 프로퍼티 키를 만들기 위해 사용된다.

 

심벌 값의 생성

1. Symbol 함수

심벌 값은 Symbol 함수를 호출하여 생성한다.

다른 원시값은 리터럴 표기법을 통해 값을 생성할 수 있지만 심벌 값은 Symbol 함수를 호출하여 생성해야 한다. 

Symbol 함수는 new 연산자와 함께 호출하지 않는다.(=Constructor X =인스턴스 생성 X)

이 때 Symbol 함수를 통해 생성된 심벌 값은 외부로 노출되지 않아 확인 할 수 없으며, 다른 값과 절대 중복되지 않는다.

심벌 값도 다른 데이터 타입처럼 객체처럼 접근하면 암묵적으로 래퍼 객체를 생성한다.

심벌 값은 암묵적으로 문자열이나 숫자 타입으로는 변환되지 않는다.

단, 불리언 타입으로는 암묵적으로 변환되므로 이를 통해 조건문 등에서 존재 확인이 가능하다.

 

2. Symbol.for / Symbol.keyFor 메소드

자바스크립트 엔진이 관리하는, 키와 심벌 값의 쌍들이 저장되어 있는 저장소인 전역 심벌 레지스트리가 있다. 

Symbol.for 메소드는 인수로 전달받은 문자열을 키로 사용하여 이 전역 심벌 레지스트리에서 해당 키와 일치하는 심벌 값을 검색한다.

 

Symbol.for 메소드

Symbol.for 메소드를 사용하면 전역에서 중복되지 않는 유일무이한 상수인 심벌 값을 단 하나만 생성하여 전역 심벌 레지스트리를 통해 공유할 수 있다.

전역 심벌 레지스트리에 인수로 넘기는 키 값이 존재하지 않으면 전역 심벌 레지스트리에 저장 후 새로운 심벌 값을 반환하고,

존재하면 해당 심벌 값을 반환한다(위 이미지!) 

 

Symbol.KeyFor 메소드는 이렇게 전역 심벌 레지스트리에 저장된 심벌 값의 키를 추출하는 메소드이다.

Symbol.for와 Symbol를 Smybol.KeyFor로 검색하는 화면

Symbol.for로 전역 시;ㅁ벌 레지스트리에 저장된 심벌 값의 키(mySymbol)를 추출할 수 있다.

 

이 때 주의해야 할 점은, 단순 Symbol 함수를 호출하면 호출할 때마다 '새로운' 심벌 값을 생성해낸다(유일무이한!).

따라서 단순 Symbol 함수로는 전역 심벌 레지스트리에 등록되어 관리되지 않는다. (캡쳐 중 아래)

 

심벌과 상수

상수 이름 자체에 의미가 있는 경우, 상수에 할당된 값은 변경될 가능성도 중복될 가능성도 존재한다.

이렇게 상수 이름 자체의 의미가 더 중요한 경우 무의미한 상수대신 Symbol을 사용할 수 있다.

const Direction = {
	UP: /*1과 같은 무의미한 상수 대신*/ Symbol.('up'),
    DOWN: Symbol.('down'),
    LEFT: Symbol.('left'),
    RIGHT: Symbol.('right')
};

const myDirection = Direction.UP;
...

 

심벌과 프로퍼티 키

앞에 프로퍼티 파트에서 설명한 것처럼 프로퍼티 키는 빈 문자열을 포함하는 모든 문자열 혹은 심벌 값으로 설정 가능하며, 프로퍼티는 동적으로 생성할 수도 있다.

이 때 심벌 값을 프로퍼티 키로 사용하려면 키로 사용할 심벌 값에 대괄호를 사용해야 한다. 프로퍼티에 접근할 때도 마찬가지로 대괄호를 사용해야 한다.

const obj = {
	[Symbol.for('mySymbol')]: 1
};

obj[Symbol.for('mySymbol')]; // ✅ 1

이렇게 심벌 값으로 프로퍼티 키를 만들면 다른 프로퍼티 키와 절대 충돌하지 않으며 미래에 추가될 프로퍼티 키와도 충돌할 위험이 없다.

 

심벌과 프로퍼티 은닉

심벌 값을 프로퍼티 키로 생성한 경우 for...in문이나 Object.keys, Object.getOwnPropertyNames 메소드로 찾을 수 없다.

이처럼 외부에 노출할 필요가 없는 프로퍼티를 심벌로 은닉할 수 있다.

 

하지만 ES6에서 도입된 Object.getOwnPropertySymbols 메소드를 사용하면 심벌 값을 프로퍼티 키로 사용한 프로퍼티를 찾을 수 있다.

const obj = {
	[Symbol.for('mySymbol')]: 1
};

// 1) 프로퍼티 은닉 할 수 있다.
for (const key in obj) {
	console.log(key); // ❌ 아무것도 출력되지 않는다.
}

// 2) Object.getOwnProperySymbols를 이용하면 인수로 전달한 객체의 심벌 프로퍼티 키를 배열로 반환한다.
console.log(Object.getOwnProperySymbols(obj)); // [Symbol(mySymbol)]

const symbolKey = Object.getOwnProperySymbols(obj)[0];
console.log(obj[symbolKey]); // ⭕ 1

 

 

심벌과 표준 빌트인 객체 확장 

일반적으로 표준 빌트인 객체는 읽기 전용으로 사용하는 것이 좋다.

개발자가 직접 추가한 메소드와 미래에 표준 사양으로 추가될 메소드의 이름이 중복될 수 있기 때문이다.

이럴 경우 표준 사양으로 추가되는 메소드가 사용자 정의 메소드에 덮어씌워지게 되고 문제가 발생할 수 있게 된다.

 

그래서 직접 빌트인 객체를 확장하는 경우 심벌 값으로 프로퍼티 키를 생성한다면 기존 프로퍼티와 충돌도 하지 않고, 미래에 추가될 수 있는 어떤 프로퍼티 키와도 충돌하지 않는게 보장이 되어 안전하게 표준 빌트인 객체를 확장할 수 있다.

 

Well-known Symbol

자바스크립트가 기본 제공하는 빌트인 심벌 값을 EMCAScript 사양에서 Well-known Symbol이라 부른다.

Well-known Symbol은 자바스크립트 엔진의 내부 알고리즘에 사용된다.

예를 들어, for ... of 문으로 순회 가능한 빌트인 이터러블 이터러블 프로토콜을 준수한 객체/34장 은 Well-known Symbol인 Symbol.iterator를 키로 갖는 메소드를 가지며 Symbol.iterator 메소드를 호출하면 이터레이터를 반환하도록 하고 있다.

 

만약 빌트인 이터러블이 아닌 일반 객체를 이터러블처럼 동작하도록 하고 싶다면, 

Well-known Symbol인 Symbol.iterator를 키로 갖는 메소드를 객체에 추가하고

이터레이터를 반환하도록 구현하면 그 객체는 이터러블이 된다.  

728x90