[TIL 25][JS] ES6 - 5

Mustache 🥸·2021년 5월 2일
0

Javascript

목록 보기
12/12

Symbol

  • symbol은 ES6에서 새롭게 추가된 타입이고 변경 불가능한 primitive 타입이다.
  • symbol은 주로 이름의 충돌 위험이 없는 unique한 객체의 프로퍼티 키를 만들기 위해 사용한다.

특징

  • Symbol은 값을 생성하여 리턴한다.
  • Symbol은 리턴된 값을 볼수가 없다.
const symbol = Symbol();
console.log(sym) // Symbol();
console.log(typeof sym) // symbol
  • 프로그램 전체의 유일한 값을 제공한다.
const one = Symbol();
const two = Symbol();
console.log(one === two) // false
  • Symbol 값으로 연산 불가
let sym = Symbol();
try {
  const add = sym + 5;
} catch {
  console.log("연산 불가);
}
// 위 경우는 연산 불가 메세지가 노출되는데, 이유는 sym값이 노출될수 있어서 symbol이 sym의 값을 주지 않아 연산이 되지 않기 떄문이다.

사용

  • Object의 프로퍼티 키로 사용 (symbol-keyed property)
    • Symbol 값이 유일하므로 중복되지 않아서
const sym = Symbol("설명");
const obj = {[sym]: 100}
console.log(obj[sym]); // 100
console.log(obj.sym);  // undefined
  • Object의 함수 이름으로 사용
const sym = Symbol("함수 이름");
const obj = {
  [sym](param){
    return param;
  }
};
console.log(obj[sym](200)); // 200
  • for in 문에서의 사용
const obj = {
  [Symbol("100")]: 100,
  two: 200
}
for (let key in obj){
  console.log(key) // two
}
// Symbol은 Enumerable이 false이기 때문에 열거 되지 않아서 two만 출력된다.
  • for of 문에서 사용
const list = [Symbol("100")];
for (let value of list){
  console.log(value) // Symbol(100)
}
  • JSON.stringify()에서의 사용
const sym = Symbol("JSON");
const result = JSON.stringify([sym]: "ABC");
console.log(result); // {}
// Symbol 값은 외부에 노출되지 않기 위해 stringify로도 변환되지 않아서 빈값이 출력된다.

Symbol Property

Symbol.toStringTag

  • Object.prototype.toString()의 확장(오버라이딩)
  • 기존 Object.toString()은 인스턴스 타입을 명확하게 구분할 수가 없었다
const Book = function(){};
const obj = new Book();
console.log(obj.toString()); // [object Object]
console.log({}.toString());  // [object Object]
// 위 처럼 결과값의 차이를 구분지을 수 없음
  • prototype에 연결하여 작성한다
const Book = function(){};
const obj = new Book();
console.log(obj.toString(); // [object Object]
Book.prototype[Symbol.toStringTag] = "해리포터";
console.log(obj.toString(); // [object 해리포터]
// Book의 prototype에 Symbol.toStringTag를 오버라이드하면 tag한 값이 나타난다

Symbol.isConcatSpreadable

  • Array.prototype.concat()은 배열의 엘리먼트를 전개하여 리턴한다.
  • 여기에 Symbol.isConcatSpreadable의 boolean값을 변경시켜줌에 따라 전개를 결정할 수 있다.
const one = [10, 20], two = ["A", "B"];
const show = () => {
  console.log(one.concat(two));
};
show(); // [10, 20, A, B]
two[Symbol.isConcatSpreadable] = true;
show(); // [10, 20, A, B]
two[Symbol.isConcatSpreadable] = false;
show(); // [10, 20, [A, B]]
  • boolean 값을 true로 하면 기존처럼 전개가 된다.
  • boolean 값을 false로 하면 배열 자체를 연결한다.

Symbol.species

  • Symbol.species는 constructor를 리턴한다.(=인스턴스를 리턴한다)
  • Symbol.species를 오버라이드하면 다른 인스턴스를 리턴할 수 있다.
  • Symbol.species는 static의 프로퍼티이며 getter는 있지만 setter는 없다
  • 아래처럼 빌트인 오브젝트를 상속받은 class에 Symbol.species를 작성하면 빌트인 오프젝트의 @@species가 오버라이드 된다.
class Sports extends Array {
  static get [Symbol.species](){
    return Array;
  }
};
const obj = new Sports(10, 20);
  • Symbol.species는 Array, Map, Set, RegExp, Promise, ArrayBuffer, TypedArray만 사용할 수 있다.

Symbol.toPrimitive

  • 오브젝트를 대응하는 Primitive 값으로 변환
  • 오브젝트를 문자열에 대응
    기존의 사용방법
const book = {
  toString() {
    return "책";
  }
};
console.log(`${book}) //책
  • 오브젝트를 숫자에 대응
const book = {
  valueOf() {
    return 30;
  }
}
console.log(book * 20) // 600

Symbol.toPrimitive의 사용

const obj = {
  [Symbol.toPrimitive](hint){
    return hint === "number" ?30;
       hint === "string" ? "책" : "default";
  }
};
console.log(20 * obj)          // 600
console.log(`${obj}` + 100)    // 책100 (`` 템플릿리터럴로 인해)
console.log(obj + 50)          // default50
console.log("default" == obj) // true

Symbol.iterator

Array

  • Array 오브젝트에서 Symbol.iterator()를 호출하면 iterator 오브젝트를 반환한다.
const list = [10, 20];
const obj = list[Symbol.iterator]();
obj.next() // {value: 10, done: false}
obj.next() // {value: 20, done: false}
obj.next() // {value: undefined, done: true}

String

  • String 오브젝트 역시 Symbol.iterator()를 호출하면 iterator 오브젝트를 반환한다.
const list "AB";
const obj = list[Symbol.iterator]();
obj.next() // {value: A, done: false}
obj.next() // {value: B, done: false}
obj.next() // {value: undefined, done: true}

Object

  • 빌트인 Object에는 Symbol.iterator가 없어서 Symbol.iterator를 직접 내부에 작성해주면 사용이 가능하다.
const obj = {
  [Symbol.iterator](){
    return {
      count: 0,
      maxCount: this.maxCount,
      next(){
        if (this.count < this.maxCount){
          return {value: this.count++, done: false}
        };
        return {value: undefined, done: true}
      }
    };
  }
};
obj.maxCount = 2;
for (const value of obj){
  console.log(value); // 0, 1
};

Symbol 함수

Symbol.for()

const one = Symbol.for("sports")
console.log(one) // Symbol(sports)
  • 글로벌 Symbol 레지스트리(Object)에 {key: value} 형태로 Symbol을 저장한다.
  • 파라미터 ()의 문자열이 key가 되고, Symbol()로 생성한 값이 value가 된다.
const one = Symbol.for("sports");
const two = Symbol.for("sports"); // one이 같은 key를 등록했으므로 two가 등록하지 않음
console.log(one === two); // true
  • 위처럼 같은 key가 존재하면 기존에 등록된 값을 사용한다.

Symbol.keyFor()

const one = Symbol.for("book");
const six = Symbol.keyFor(one);
console.log(six) // book
  • 글로벌 Symbol 레지스트리에서 Symbol의 key 값을 구해온다.
  • key 값이 존재하면 key 값을 리턴하고 존재하지 않으면 undefined를 리턴한다.

Symbol.prototype.toString()

console.log(Symbol("100").toString(); // Symbol(100)
const sym = Symbol.for("book");
console.log(sym.toString());          // Symbol(book)
try {
  console.log(Symbol() + "ABC");
} catch {
  console.log("+로 연결 불가");          // +로 연결 불가
};
  • Symbol을 생성했던 형태를 문자열로 변환하여 리턴(Symbol 값은 리턴하지 않음)
  • +로 문자열을 연결하면 TypeError가 난다. toString()으로 변환하면 연결은 되지만 Symbol값은 연결되지 않는다.

Symbol.prototype.valueOf()

console.log(Symbol("100").valueOf());     // Symbol(100)
console.log(Symbol.for("200").valueOf()); // Symbol(200)
  • 기존 valueOf()가 프리미티브 값을 반환하지만 Symbol은 값을 반환하지 않고 Symbol을 생성한 형태를 리턴한다.
  • Symbol.for()는 for를 제외하고 리턴한다.

0개의 댓글