html,css,js

[자바스크립트 중급] 심볼(Symbol)

코복이 2023. 5. 4. 19:01
728x90

1. 들어가며

JavaScript의 타입은 총 7가지다. // typeof 로 조회해봐
- 6개의 원시 타입(number, string, boolean, null, undefined, symbol)
- 1개의 객체 타입(object)
 
심볼(symbol) 타입은 원시 타입 중 하나로, es6 버전에서 새롭게 추가되었다.
다른 타입에 비해 흔하게 사용되는 타입은 아니지만, JavaScript에는 심볼 타입에 대한 이해가 전제되어야 이해하고 사용할 수 있는 몇몇 문법(EX. iterable 객체)들도 있기 때문에 공부해두는 것이 좋다.

 
 

2. 심볼 (Symbol)

  • 심볼 타입은 객체의 프로퍼티 키를 고유하게 설정함으로써 프로퍼티 키의 충돌을 방지하기 위해 사용된다.
  • Symbol 코드 작성시, S는 대문자로 써야 함.
  • 유일성이 보장 됨. 전체 코드중에 이건 one & only다.
// Symbol 특징 (one & only 키값을 만들어줌)
const a = Symbol();
const b = Symbol();

const c = Symbol("설명"); //이 심볼에 대한 설명은 작성해주는 것이 좋다. 코드 작동에 아무런 영향 없음.
const d = Symbol("설명");

console.log(a === b); // false
console.log(c === d); // false
  • 자바스크립트에서 객체의 프로퍼티 키는 대개 문자열 값이다. 숫자로 쓰는 것도 사실은 문자열이다(숫자로 써도 반환은 문자로 됨
  • 이때, 문자열 값 대신 심볼도 프로퍼티 키로 사용될 수 있다. 이 경우, 기본적으로 심볼은 고유하기 때문에 심볼을 키로 갖는 프로퍼티는 다른 어떤 프로퍼티와도 충돌하지 않을 것이다.
  • Symbol 타입 키는 숨어있다 (일반적으로는 조회가 안된다)
// 심볼 타입 property key
const id = Symbol("회원 아이디");
const user1 = {
    name: "Mike",
    age: 30,
    [id]: "id1" // id 라는 '변수'가 들어가야 하니까 [id]이렇게 computed property 씀
}

// Symbol은 이런 방법으로는 안나옴
console.log(user1); // { name: 'Mike', age: 30, [Symbol(회원 아이디)]: 'id1' }
console.log(user1[id]); // id1
console.log(Object.keys(user1)); // [ 'name', 'age' ]
console.log(Object.values(user1)); // [ 'Mike', 30 ]
console.log(Object.entries(user1)); // [ [ 'name', 'Mike' ], [ 'age', 30 ] ]
for(let key in user1){console.log(key)}; // name age
for(let key in user1){console.log(user1[key])}; // Mike 30
  • 조회가 안되는 것을 이용해서 특정 객체에 원본 프로퍼티는 건들이지 않고 프로퍼티를 추가할 수 있음.
  • 숨겨진 Symbol 타입 키 보는 법 1  Object.getOwnPropertySymbols(객체명)
  • 숨겨진 Symbol 타입 키 보는 법 2 Reflect.ownKeys(객체명)
// 숨겨진 심볼 보는 법
const userId = Symbol("회원아이디");

const user1 = {
    [userId]: "id1",
    name: "mimi",
    age: 30
}

console.log(Object.keys(user1)); // [ 'name', 'age' ] (심볼 타입 키는 안나옴)
console.log(Object.getOwnPropertySymbols(user1)); // [ Symbol(회원아이디) ]
console.log(Reflect.ownKeys(user1)); // [ 'name', 'age', Symbol(회원아이디) ]

 

 

3. Symbol.for() : 전역 심볼 

  • 인자로 전달받은 값("설명부분")을 키로 갖는 심볼을 전역 심볼 레지스트리에서 찾아 반환하고, 탐색에 실패한다면 그 문자열 값을 키로 갖는 심볼을 새로 생성하여 전역 심볼 레지스트리에 저장한 뒤 이를 반환한다. (있으면 동일한 심볼로 만들어주고 없으면 새로운 심볼 만들어)
  • Symbol() 함수는 매번 다른 Symbol 값을 생성하지만, Symbol.for() 메소드는 하나를 생성한뒤 키를 통해 같은 Symbol을 공유한다.
  • 같은 심볼인지는 "설명" 부분이 동일하면 동일한 심볼이라고 여김
// Symbol.for 전역심볼
const id1 = Symbol.for("회원 아이디");
const id2 = Symbol.for("회원 아이디");

const id3 = Symbol.for("회원 아이디1");
const id4 = Symbol.for("회원 아이디2");

console.log(id1 === id2); // true
console.log(id3 === id4); // false (설명 부분이 다름)

 
 

4. Symbol.keyfor(변수명) : 전역 심볼의 '설명' 조회

  • 전역 심볼의 '설명' 조회할 때 사용
const id3 = Symbol.for("회원 아이디1");
const id4 = Symbol.for("회원 아이디2");

console.log(Symbol.keyFor(id3)); // 회원 아이디1
  • 일반 심볼은 심볼명.decription; 으로 조회해야 함(전역심볼도 조회 됨) 
// 전역심볼과 일반심볼 설명 조회 차이
const id1 = Symbol("회원 아이디1");
const id2 = Symbol.for("회원 아이디2");

console.log(Symbol.keyFor(id1)); // undefined
console.log(id1.description); // 회원아이디1
console.log(Symbol.keyFor(id2)); // 회원아이디2
console.log(id2.description); // 회원아이디2

 
 
📌 심볼 사용 예제

  • 기존 개발자가 만들어 놓은 객체와 객체 이용한 코드가 있는데 내가 중간에 객체에 메서드 추가하고 싶어짐.
// 기존 객체 (다른 개발자가 만들어 놓음)
const user1 = {
    name: "Mike",
    age: 30
};

// 중간에 내가 작업 (기존 객체에 메서드 추가하고 싶음)
user1.showName = function(){};

// 사용자가 접속하면 보는 메시지 (다른 개발자가 만들어 놓음)
for(let key in user1){
    console.log(`나의 ${key}${user1[key]}입니다`)
};
나의 name은 Mike입니다
나의 age은 30입니다
나의 showName은 function(){}입니다 // 이렇게 메시지가 이상해짐

==>

// 기존 객체 (다른 개발자가 만들어 놓음)
const user1 = {
    name: "Mike",
    age: 30
};

// 심볼 활용하여 기존 코드 충돌 없고 메서드도 정상 실행되게 함.
const showName = Symbol("이름을 알려주는 메서드");
user1[showName] = function () {
    console.log(`제 이름은 ${this.name}입니다`)
}

// 사용자가 접속하면 보는 메시지 (다른 개발자가 만들어 놓음)
for(let key in user1){
    console.log(`나의 ${key}${user1[key]}입니다`)
};

// 새로 추가한 메서드 실행
user1[showName]();
 
나의 name은 Mike입니다
나의 age은 30입니다 // for in 문에 심볼은 안나옴
제 이름은 Mike입니다 // 심볼로 추가한 메서드 실행

 
※ 근데 이건 미봉책 아닌가,,?

728x90