JavaScript의 심볼에 대한 실용 안내서
본문
JavaScript는 속성 이름 충돌을 방지하기 위해 ES6에서 심볼을 도입했습니다. 또한 보너스는 2015-2019 JavaScript에서 개인 속성을 시뮬레이션 하는 방법을 제공합니다.
소개
JavaScript에서 심볼을 만드는 가장 간단한 방법은 Symbol() 함수를 호출하는 것입니다. 심볼을 특별하게 만드는 2 가지 주요 속성은 다음과 같습니다.
- 객체 키로 심볼을 사용할 수 있습니다. 문자열과 심볼만 객체 키로 사용할 수 있습니다.
- 두 개의 심볼은 동일하지 않습니다.
const symbol1 = Symbol();
const symbol2 = Symbol();
symbol1 === symbol2; // false
const obj = {};
obj[symbol1] = 'Hello';
obj[symbol2] = 'World';
obj[symbol1]; // 'Hello'
obj[symbol2]; // 'World'
Symbol() 호출로 인해 심볼이 객체처럼 보이지만 실제로는 심볼이 JavaScript의 기본 유형입니다. new를 사용하여 생성자로 Symbol을 사용하면 오류가 발생합니다.
const symbol1 = Symbol();
typeof symbol1; // 'symbol'
symbol1 instanceof Object; // false
// Throws "TypeError: Symbol is not a constructor"
new Symbol();
설명
Symbol() 함수는 단일 매개 변수인 문자열 설명을 사용합니다. 심볼의 설명은 디버깅 목적으로만 사용됩니다. 설명은 심볼의 toString()에 표시됩니다. 그러나 동일한 설명을 가진 두 개의 심볼은 동일하지 않습니다.
const symbol1 = Symbol('my symbol');
const symbol2 = Symbol('my symbol');
symbol1 === symbol2; // false
console.log(symbol1); // 'Symbol(my symbol)'
글로벌 심볼 레지스트리도 있습니다. Symbol.for()를 사용하여 심볼을 만들면 심볼 설명에 따라 키를 전역 레지스트리에 추가합니다. 즉, Symbol.for()를 사용하여 동일한 설명으로 두 개의 심볼을 만들면 두 심볼이 동일합니다.
const symbol1 = Symbol.for('test');
const symbol2 = Symbol.for('test');
symbol1 === symbol2; // true
console.log(symbol1); // 'Symbol(test)'
일반적으로 명명 충돌이 발생할 수 있으므로 적절한 이유가 없는 한 전역 기호 레지스트리를 사용하면 안됩니다.
이름 충돌
JavaScript의 첫 번째 기본 제공 심볼은 ES6의 Symbol.iterator 심볼입니다. Symbol.iterator 함수가 있는 객체는 반복 가능한 것으로 간주됩니다. 즉, 해당 객체를 for / of 루프의 오른쪽으로 사용할 수 있습니다.
const fibonacci = {
[Symbol.iterator]: function*() {
let a = 1;
let b = 1;
let temp;
yield b;
while (true) {
temp = a;
a = a + b;
b = temp;
yield b;
}
}
};
// Prints every Fibonacci number less than 100
for (const x of fibonacci) {
if (x >= 100) {
break;
}
console.log(x);
}
Symbol.iterator가 문자열이 아닌 심볼인 이유는 무엇입니까? Symbol.iterator를 사용하는 대신 iterable 스펙에서 문자열 특성 'iterator'가 있는지 확인했다고 가정하십시오. 또한 반복 가능 해야 하는 아래 클래스가 있다고 가정하십시오.
class MyClass {
constructor(obj) {
Object.assign(this, obj);
}
iterator() {
const keys = Object.keys(this);
let i = 0;
return (function*() {
if (i >= keys.length) {
return;
}
yield keys[i++];
})();
}
}
MyClass의 인스턴스는 객체의 키를 반복 할 수 있는 반복 가능한 객체입니다. 그러나 위의 클래스에는 잠재적 인 결함이 있습니다. 악의적인 사용자가 반복자 속성을 가진 객체를 MyClass로 전달한다고 가정합니다.
const obj = new MyClass({ iterator: 'not a function' });
obj에 for / of를 사용하면 JavaScript에서 TypeError가 발생합니다. obj는 반복 가능하지 않습니다. 사용자 지정 반복자 함수가 클래스의 반복자 속성을 덮어 쓰기 때문입니다. 이는 사용자 데이터를 순진하게 복사하면 __proto__ 및 생성자와 같은 특수 속성에 문제가 발생할 수 있는 프로토 타입 오염과 유사한 보안 문제입니다.
여기서 핵심 패턴은 기호가 사용자 데이터와 객체의 프로그램 데이터를 명확하게 구분할 수 있다는 것입니다. JSON에서 기호를 표현할 수 없으므로 Symbol.iterator 속성이 잘못된 Express API로 데이터가 전달 될 위험이 없습니다. 사용자 데이터와 Mongoose 모델과 같은 내장 함수 및 메소드를 혼합하는 객체에서 기호를 사용하여 사용자 데이터가 내장 기능과 충돌하지 않도록 할 수 있습니다.
개인(Private) 속성
두 개의 기호가 동일하지 않으므로 기호는 JavaScript에서 개인 속성을 시뮬레이션 하는 편리한 방법입니다. 심볼은 Object.keys ()에 표시되지 않으므로 심볼을 명시 적으로 내 보내지 않으면 명시 적으로 Object.getOwnPropertySymbols () 함수를 거치지 않으면 다른 코드에서 해당 속성에 액세스 할 수 없습니다.
function getObj() {
const symbol = Symbol('test');
const obj = {};
obj[symbol] = 'test';
return obj;
}
const obj = getObj();
Object.keys(obj); // []
// Unless you explicitly have a reference to the symbol, you can't access the
// symbol property.
obj[Symbol('test')]; // undefined
// You can still get a reference to the symbol using `getOwnPropertySymbols()`
const [symbol] = Object.getOwnPropertySymbols(obj);
obj[symbol]; // 'test'
JSON.stringify() 출력에 표시되지 않기 때문에 기호는 개인 속성에도 편리합니다. 특히 JSON.stringify()는 기호 키와 값을 자동으로 무시합니다.
const symbol = Symbol('test');
const obj = { [symbol]: 'test', test: symbol };
JSON.stringify(obj); // "{}"
계속
심볼은 사용자 데이터가 프로그램 상태와 분리 된 상태를 유지하면서 개체의 내부 상태를 나타내는 데 유용한 도구입니다. 심볼을 사용하면 프로그램 상태 속성 앞에 '$'를 접두어로 붙이는 등의 규칙이 더 이상 필요하지 않습니다. 다음에 객체 속성을 $$ __ internalFoo로 설정하면 심볼을 대신 사용해보십시오.
http://thecodebarbarian.com/a-practical-guide-to-symbols-in-javascript.html
- 이전글Day.js 19.08.31
- 다음글PHP 코딩 표준 문제를 자동으로 해결하는 도구 19.08.31