es6 symbol 의 실현 방법 예시

9153 단어 es6symbol
배경
ES5 의 대상 속성 명 은 모두 문자열 로 속성 명 이 충돌 하기 쉽다.예 를 들 어 다른 사람 이 제공 하 는 대상 을 사 용 했 지만 이 대상 에 게 새로운 방법(mixin 모드)을 추가 하려 면 새로운 방법의 이름 이 기 존 방법 과 충돌 할 수 있 습 니 다.만약 에 하나의 메커니즘 이 있다 면 모든 속성의 이름 이 유일무이한 것 이 었 으 면 좋 겠 습 니 다.그러면 근본적으로 속성 명의 충돌 을 방지 할 수 있 습 니 다.ES6 가 심 볼 을 도입 한 이유 다.
ES6 는 유일한 값 을 나타 내 는 새로운 원본 데이터 형식 Symbol 을 도입 했다.이것 은 자 바스 크 립 트 언어의 일곱 번 째 데이터 형식 입 니 다.여섯 번 째 는 undefined,null,불 값(Boolean),문자열(String),수치(Number),대상(Object)입 니 다.
Symbol 값 은 Symbol 함 수 를 통 해 생 성 됩 니 다.대상 의 속성 명 은 현재 두 가지 유형 이 있 을 수 있 으 며,하 나 는 원래 있 던 문자열 이 고,다른 하 나 는 새로 추 가 된 Symbol 형식 이다.속성 명 이 Symbol 유형 에 속 하 는 것 은 모두 유일무이한 것 으로 다른 속성 명 과 충돌 하지 않 을 것 을 보증 할 수 있 습 니 다.

let s = Symbol();

typeof s
// "symbol"
위의 코드 에서 변수 s 는 유일한 값 입 니 다.type:of 연산 자의 결 과 는 변수 s 가 문자열 과 같은 다른 형식 이 아니 라 Symbol 데이터 형식 임 을 나타 낸다.
Symbol 함수 전에 new 명령 을 사용 할 수 없습니다.그렇지 않 으 면 오류 가 발생 할 수 있 습 니 다.생 성 된 Symbol 은 대상 이 아 닌 원본 형식의 값 이기 때문이다.심 볼 값 이 대상 이 아니 기 때문에 속성 을 추가 할 수 없다 는 것 이다.기본적으로 문자열 과 유사 한 데이터 형식 입 니 다.
Symbol 함 수 는 하나의 문자열 을 매개 변수 로 받 아들 여 Symbol 인 스 턴 스 에 대한 설명 을 표시 할 수 있 습 니 다.주로 콘 솔 에 표시 하거나 문자열 로 전환 할 때 쉽게 구분 할 수 있 습 니 다.

let s1 = Symbol('foo');
let s2 = Symbol('bar');

s1 // Symbol(foo)
s2 // Symbol(bar)

s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"

위의 코드 중 s1 과 s2 는 두 개의 Symbol 값 입 니 다.파 라 메 터 를 추가 하지 않 으 면 콘 솔 에서 출력 하 는 것 은 모두 Symbol()이 므 로 구분 하기에 불리 합 니 다.매개 변수 가 있 으 면 설명 을 더 한 것 과 같 습 니 다.출력 할 때 어떤 값 인지 구분 할 수 있 습 니 다.
Symbol 의 인자 가 대상 이 라면 대상 의 toString 방법 을 호출 하여 문자열 로 변환 한 다음 Symbol 값 을 생 성 합 니 다.

const obj = {
 toString() {
  return 'abc';
 }
};
const sym = Symbol(obj);
sym // Symbol(abc)
Symbol 함수 의 매개 변 수 는 현재 Symbol 값 에 대한 설명 만 표시 하기 때문에 같은 매개 변수의 Symbol 함수 의 반환 값 은 같 지 않 습 니 다.

//        
let s1 = Symbol();
let s2 = Symbol();

s1 === s2 // false

//       
let s1 = Symbol('foo');
let s2 = Symbol('foo');

s1 === s2 // false

위의 코드 에서 s1 과 s2 는 모두 Symbol 함수 의 반환 값 이 고 매개 변 수 는 같 지만 같 지 않 습 니 다.
Symbol 값 은 다른 유형의 값 과 연산 할 수 없 으 며 오류 가 발생 할 수 있 습 니 다.

let sym = Symbol('My symbol');

"your symbol is " + sym
// TypeError: can't convert symbol to string
`your symbol is ${sym}`
// TypeError: can't convert symbol to string
속성 명 Symbol
모든 Symbol 값 이 같 지 않 기 때문에 Symbol 값 은 식별 자로 사용 할 수 있 고 대상 의 속성 명 에 사용 하면 같은 이름 의 속성 이 나타 나 지 않 음 을 보증 할 수 있 습 니 다.이것 은 한 대상 이 여러 모듈 로 구 성 된 상황 에 매우 유용 하 며,어떤 키 가 부주의 로 고 쳐 쓰 거나 덮어 쓰 는 것 을 방지 할 수 있다.

let mySymbol = Symbol();

//      
let a = {};
a[mySymbol] = 'Hello!';

//      
let a = {
 [mySymbol]: 'Hello!'
};

//      
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });

//            
a[mySymbol] // "Hello!"
위의 코드 는 괄호 구조 와 Object.defineProperty 를 통 해 대상 의 속성 명 을 Symbol 값 으로 지정 합 니 다.
Symbol 값 이 대상 속성 명 일 때 점 연산 자 를 사용 할 수 없습니다.

const mySymbol = Symbol();
const a = {};

a.mySymbol = 'Hello!';
a[mySymbol] // undefined
a['mySymbol'] // "Hello!"

위의 코드 에 서 는 점 연산 자 뒤에 항상 문자열 이 있 기 때문에 my Symbol 이 표지 명 으로 가리 키 는 값 을 읽 지 않 습 니 다.이 로 인해 a 의 속성 명 은 Symbol 값 이 아 닌 문자열 입 니 다.
마찬가지 로 대상 내부 에서 Symbol 값 으로 속성 을 정의 할 때 Symbol 값 은 괄호 안에 넣 어야 합 니 다.

let s = Symbol();

let obj = {
 [s]: function (arg) { ... }
};

obj[s](123);

위의 코드 에서 s 가 괄호 에 넣 지 않 으 면 이 속성의 키 이름 은 s 가 대표 하 는 Symbol 값 이 아 닌 문자열 s 입 니 다.
강 화 된 대상 쓰기 로 위 코드 의 obj 대상 을 좀 더 간결 하 게 쓸 수 있 습 니 다.

let obj = {
 [s](arg) { ... }
};
Symbol 형식 은 한 그룹의 상수 도 정의 할 수 있 으 며,이 그룹의 상수 값 이 모두 같 지 않 음 을 보증 합 니 다.

const log = {};

log.levels = {
 DEBUG: Symbol('debug'),
 INFO: Symbol('info'),
 WARN: Symbol('warn')
};
console.log(log.levels.DEBUG, 'debug message');
console.log(log.levels.INFO, 'info message');

3 인 스 턴 스:마술 문자열 제거
마술 문자열 은 코드 에 여러 번 나타 나 코드 와 강 한 결합 을 이 루 는 구체 적 인 문자열 이나 수 치 를 말한다.스타일 이 좋 은 코드 는 마술 문자열 을 최대한 없 애고 의미 가 뚜렷 한 변수 로 대체 해 야 합 니 다.

function getArea(shape, options) {
 let area = 0;

 switch (shape) {
  case 'Triangle': //      
   area = .5 * options.width * options.height;
   break;
  /* ... more code ... */
 }

 return area;
}

getArea('Triangle', { width: 100, height: 100 }); //      
위의 코드 에서 문자열 Triangle 은 마술 문자열 입 니 다.그것 은 여러 차례 출현 하여 코드 와'강 한 결합'을 형성 하여 미래의 수정 과 유지 에 불리 하 다.
마술 문자열 을 없 애 는 데 자주 사용 되 는 방법 은 변 수 를 쓰 는 것 이다.

const shapeType = {
 triangle: 'Triangle'
};

function getArea(shape, options) {
 let area = 0;
 switch (shape) {
  case shapeType.triangle:
   area = .5 * options.width * options.height;
   break;
 }
 return area;
}

getArea(shapeType.triangle, { width: 100, height: 100 });
위의 코드 에서 우 리 는 Triangle 을 shapeType 대상 의 triangle 속성 으로 써 서 강 한 결합 을 없 앴 다.
자세히 분석 하면 shapeType.triangle 이 어떤 값 인지 중요 하지 않 습 니 다.다른 shapeType 속성의 값 과 충돌 하지 않도록 확보 하면 됩 니 다.따라서 이곳 은 Symbol 값 으로 바 꾸 기 에 적합 하 다.

const shapeType = {
 triangle: Symbol()
};
4 속성 명 옮 겨 다 니 기
Symbol 은 속성 명 으로서 이 속성 은 for...in,for...of 순환 에 나타 나 지 않 고 Object.keys(),Object.getOwnProperty Names(),JSON.stringify()에 의 해 되 돌아 오지 않 습 니 다.그러나 이것 은 개인 속성 도 아 닙 니 다.Object.getOWn Property Symbols 방법 이 있 습 니 다.지정 한 대상 의 모든 Symbol 속성 명 을 얻 을 수 있 습 니 다.
Object.getOwnProperty Symbols 방법 은 하나의 배열 을 되 돌려 줍 니 다.구성원 은 현재 대상 의 모든 속성 명 으로 사용 되 는 Symbol 값 입 니 다.

const obj = {};
let a = Symbol('a');
let b = Symbol('b');

obj[a] = 'Hello';
obj[b] = 'World';

const objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols
// [Symbol(a), Symbol(b)]
다음은 또 다른 예 입 니 다.Object.getOWn Property Symbols 방법 과 for...in 순환,Object.getOWn Property Names 방법 을 비교 한 예 입 니 다.

const obj = {};

let foo = Symbol("foo");

Object.defineProperty(obj, foo, {
 value: "foobar",
});

for (let i in obj) {
 console.log(i); //    
}

Object.getOwnPropertyNames(obj)
// []

Object.getOwnPropertySymbols(obj)
// [Symbol(foo)]
위의 코드 에 서 는 Object.getOwnProperty Names 방법 으로 Symbol 속성 명 을 얻 을 수 없 으 며,Object.getOwnProperty Symbols 방법 을 사용 해 야 합 니 다.
또 다른 새로운 API,Reflect.ownKeys 방법 은 일반적인 키 이름과 Symbol 키 를 포함 한 모든 종류의 키 이름 을 되 돌려 줍 니 다.

let obj = {
 [Symbol('my_key')]: 1,
 enum: 2,
 nonEnum: 3
};

Reflect.ownKeys(obj)
// ["enum", "nonEnum", Symbol(my_key)]

5 Symbol.for(),Symbol.keyFor()
때때로 우 리 는 같은 Symbol 값 을 다시 사용 하고 싶 습 니 다.Symbol.for 방법 으로 이 점 을 할 수 있 습 니 다.문자열 을 매개 변수 로 받 아들 인 다음 이 매개 변 수 를 이름 으로 하 는 Symbol 값 이 있 는 지 검색 합 니 다.있 으 면 이 Symbol 값 을 되 돌려 줍 니 다.그렇지 않 으 면 이 문자열 이름 의 Symbol 값 을 새로 만 들 고 되 돌려 줍 니 다.

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');

s1 === s2 // true

위의 코드 에서 s1 과 s2 는 모두 Symbol 값 이지 만 모두 같은 매개 변수의 Symbol.for 방법 으로 생 성 되 었 기 때문에 실제 적 으로 같은 값 입 니 다.
Symbol.for()와 Symbol()두 가지 표기 법 은 모두 새로운 Symbol 을 생 성 합 니 다.이들 의 차 이 는 전 자 는 전체 환경 에 등록 되 어 검색 할 수 있 고 후 자 는 그렇지 않다 는 것 이다.Symbol.for()는 호출 할 때마다 새로운 Symbol 형식의 값 을 되 돌려 주지 않 고 주어진 key 가 존재 하 는 지 확인 합 니 다.존재 하지 않 으 면 새 값 을 만 듭 니 다.예 를 들 어 Symbol.for("cat")를 30 번 호출 하면 매번 같은 Symbol 값 을 되 돌려 주지 만 Symbol("cat")을 30 번 호출 하면 30 개의 다른 Symbol 값 을 되 돌려 줍 니 다.
Symbol.keyFor 방법 은 등 록 된 Symbol 형식 값 의 key 를 되 돌려 줍 니 다.

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined

위의 코드 에서 변수 s2 는 등록 되 지 않 은 Symbol 값 에 속 하기 때문에 undefined 로 돌아 갑 니 다.
주의해 야 할 것 은 Symbol.for 가 Symbol 값 으로 등 록 된 이름 은 전역 환경 이 므 로 서로 다른 iframe 이나 service worker 에서 같은 값 을 찾 을 수 있 습 니 다.

iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);

iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo')
// true
위의 코드 에서 iframe 창 에서 생 성 된 Symbol 값 은 홈 페이지 에서 얻 을 수 있 습 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기