[javascript] ES6에 Symbol을 가져 오는 동기는 무엇입니까?

업데이트 : 최근 Mozilla훌륭한 기사가 나왔습니다. 궁금하다면 읽어보십시오.

아시다시피 ECMAScript 6에 새로운 Symbol 프리미티브 유형 을 포함계획입니다 (다른 미친 것들은 말할 것도 없습니다). 나는 :symbol루비 의 개념이 불필요 하다고 항상 생각했다 . JavaScript 에서처럼 일반 문자열을 쉽게 사용할 수 있습니다. 그리고 이제 그들은 JS의 것들을 복잡하게하기로 결정했습니다.

나는 동기를 이해하지 못한다. 자바 스크립트에서 실제로 기호가 필요한지 설명해 줄 수 있습니까?



답변

Javascript에 심볼을 도입하려는 원래 동기는 개인 속성 을 활성화하는 것이 었습니다 .

불행하게도, 그들은 심각하게 다운 그레이드되었습니다. 예를 들어, Object.getOwnPropertySymbols프록시를 사용하여 리플렉션을 통해 찾을 수 있으므로 더 이상 비공개 입니다.

이제는 고유 한 기호 로 알려져 있으며 속성 간의 이름 충돌을 피하기위한 용도로만 사용됩니다. 예를 들어 ECMAScript 자체는 사용자 이름과 충돌 할 위험없이 객체에 배치 할 수있는 특정 방법 (예 : 반복 프로토콜 정의)을 통해 확장 후크를 도입 할 수 있습니다.

언어에 기호를 추가하려는 동기가 충분히 강력한 지 여부는 논란의 여지가 있습니다.


답변

기호는 진정한 개인 정보 보호를 보장하지는 않지만 객체의 공용 속성과 내부 속성을 분리하는 데 사용할 수 있습니다. Symbol개인 속성을 갖는 데 사용할 수있는 예를 살펴 보겠습니다 .

객체의 속성이 비공개가 아닌 경우를 예로 들어 봅시다.

var Pet = (function() {
  function Pet(type) {
    this.type = type;
  }
  Pet.prototype.getType = function() {
    return this.type;
  }
  return Pet;
}());

var a = new Pet('dog');
console.log(a.getType());//Output: dog
a.type = null;
//Modified outside
console.log(a.getType());//Output: null

위의 Pet클래스 속성 type은 비공개가 아닙니다. 비공개로하려면 클로저를 만들어야합니다. 아래 예제 type는 클로저를 사용하여 비공개로 만드는 방법을 보여줍니다 .

var Pet = (function() {
  function Pet(type) {
    this.getType = function(){
      return type;
    };
  }
  return Pet;
}());

var b = new Pet('dog');
console.log(b.getType());//dog
b.type = null;
//Stays private
console.log(b.getType());//dog

위의 접근 방식의 단점 : Pet생성 된 각 인스턴스 에 대해 추가적인 폐쇄를 도입하여 성능을 저하시킬 수 있습니다.

이제 우리는 소개 Symbol합니다. 이를 통해 불필요한 추가 폐쇄를 사용하지 않고 개인 재산을 만들 수 있습니다. 아래 코드 예 :

var Pet = (function() {
  var typeSymbol = Symbol('type');
  function Pet(type) {
    this[typeSymbol] = type;
  }
  Pet.prototype.getType = function(){
    return this[typeSymbol];
  }
  return Pet;
}());

var a = new Pet('dog');
console.log(a.getType());//Output: dog
a.type = null;
//Stays private
console.log(a.getType());//Output: dog


답변

Symbols객체에서 고유 한 속성 이름으로 사용할 수있는 새롭고 특별한 종류의 객체입니다. Symbol대신에를 사용 string하면 서로 다른 모듈이 서로 충돌하지 않는 속성을 만들 수 있습니다. Symbols은 (는) 비공개로 만들 수 있으므로 아직에 직접 액세스하지 않은 사람은 속성에 액세스 할 수 없습니다 Symbol.

Symbols새로운 프리미티브 입니다. 그냥 같은 number, string그리고 boolean프리미티브 Symbol를 생성하는 데 사용할 수있는 기능을 가지고있다. 다른 프리미티브와 달리 Symbols리터럴 구문은 없습니다 (예 : how stringhave '').이를 생성하는 유일한 방법 Symbol은 다음과 같은 방법으로 생성자를 사용하는 것입니다.

let symbol = Symbol();

실제로 Symbol는 객체에 속성을 첨부하는 약간 다른 방법 입니다 . 상속 된 모든 항목에 나타나는 Symbols것처럼 표준 메서드를 쉽게 제공 할 수 있습니다 .Object.prototype.hasOwnPropertyObject

다음은 Symbol기본 유형 의 장점 중 일부입니다 .

Symbols 디버깅 기능이 내장되어 있습니다

Symbols 콘솔에 로깅 할 때 인생을 조금 더 쉽게하기 위해 디버깅에 실제로 사용되는 설명을 제공 할 수 있습니다.

SymbolsObject키로 사용할 수 있습니다

이곳이 Symbol정말 흥미로워 지는 곳 입니다. 그것들은 물체와 크게 얽혀 있습니다. Symbol객체에 키로 할당 할 수 있습니다. 즉, 객체에 고유 한 수를 무제한으로 할당 할 수 Symbol있으며 string키 또는 다른 고유 한 객체와 충돌하지 않도록 보장 할 수 있습니다 Symbols.

Symbols 고유 한 값으로 사용할 수 있습니다.

하자가 같은 여러 개의 로그 수준을 포함하는 로깅 라이브러리가 가정 logger.levels.DEBUG, logger.levels.INFO, logger.levels.WARN등을. ES5 코드에서는 이것을 strings (so logger.levels.DEBUG === 'debug') 또는 numbers ( logger.levels.DEBUG === 10)로 만들고 싶습니다 . 이러한 값은 고유 한 값이 아니기 때문에 이상적이지 않지만 Symbols는 이상적입니다 ! 따라서 logger.levels간단히 다음과 같습니다.

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

위대한 기사 에서 더 많은 것을 읽으십시오 .


답변

이 게시물은 Symbol()내가 찾거나 만들 수있는 실제 예제와 내가 찾을 수있는 사실 및 정의와 함께 제공됩니다.

TLDR;

Symbol()ECMAScript를 6 (ES6)의 방출 도입 데이터 형식이다.

Symbol에 대한 두 가지 흥미로운 사실이 있습니다.

  • 리터럴이없는 JavaScript의 첫 번째 데이터 유형 및 유일한 데이터 유형

  • 로 정의 된 모든 변수 Symbol()는 고유 한 콘텐츠를 얻지 만 실제로는 비공개 가 아닙니다 .

  • 모든 데이터에는 자체 Symbol 이 있으며 동일한 데이터에 대해 Symbols는 동일 합니다. 다음 단락에서 더 많은 정보, 그렇지 않으면 TLRD가 아닙니다. 🙂

심볼을 어떻게 초기화합니까?

1. 디버깅 가능한 값을 가진 고유 식별자를 얻으려면

이 방법으로 할 수 있습니다 :

var mySymbol1 = Symbol();

또는이 방법 :

var mySymbol2 = Symbol("some text here");

"some text here"문자열이 기호에서 추출 할 수 없습니다, 그것은 디버깅 목적으로 만 설명입니다. 어떤 식 으로든 기호 동작을 변경하지 않습니다. 비록 당신이 할 수는 console.log있지만 (값은 디버깅을위한 것이므로 다른 로그 항목으로 그 로그를 착각하지 않도록)

console.log(mySymbol2);
// Symbol(some text here)

2. 일부 문자열 데이터에 대한 기호를 얻으려면

이 경우 심볼의 값이 실제로 고려되며이 방식으로 두 심볼이 고유하지 않을 수 있습니다.

var a1 = Symbol.for("test");
var a2 = Symbol.for("test");
console.log(a1 == a2); //true!

이러한 기호를 “두 번째 유형”기호라고합니다. Symbol(data)어떤 식 으로든 “첫 번째 유형”기호 (예 :로 정의 된 기호)와 교차하지 않습니다 .

다음 두 단락은 첫 번째 유형 기호 에만 해당 됩니다.

이전 데이터 유형 대신 Symbol을 사용하면 어떤 이점이 있습니까?

먼저 표준 데이터 유형 인 객체를 고려해 봅시다. 키-값 쌍을 정의하고 키를 지정하여 값에 액세스 할 수 있습니다.

var persons = {"peter":"pan","jon":"doe"};
console.log(persons.peter);
// pan

Peter라는 이름을 가진 두 사람이 있다면 어떨까요?

이것을하는 것 :

var persons = {"peter":"first", "peter":"pan"};

별로 이해가되지 않습니다.

따라서 같은 이름을 가진 두 명의 완전히 다른 사람의 문제인 것 같습니다. 그런 다음 new를 참조하십시오 Symbol(). 실생활의 사람 과 같습니다. 모든 사람은 독특 하지만 이름은 동일 할 수 있습니다. 두 “사람”을 정의합시다.

 var a = Symbol("peter");
 var b = Symbol("peter");

이제 같은 이름을 가진 두 사람이 있습니다. 우리의 사람들은 실제로 다른가? 그들은; 당신은 이것을 확인할 수 있습니다 :

 console.log(a == b);
 // false

우리는 어떻게 유익합니까?

우리는 다른 사람을 위해 당신의 물건에 두 개의 항목을 만들 수 있으며 어떤 식 으로든 착각 할 수 없습니다.

 var firstPerson = Symbol("peter");
 var secondPerson = Symbol("peter");
 var persons = {[firstPerson]:"first", [secondPerson]:"pan"};

참고 :
객체를 문자열 화하면 JSON.stringifySymbol로 키로 초기화 된 모든 쌍이 삭제됩니다.
실행 Object.keys은 그러한 Symbol()->value쌍을 반환하지 않습니다 .

이 초기화를 사용하면 첫 번째 사람과 두 번째 사람의 항목을 착각하는 것은 절대 불가능합니다. 전화 console.log하면 두 번째 이름이 올바르게 출력됩니다.

 console.log(persons[a]);
 // first
 console.log(persons[b]);
 // pan

객체에 사용될 때 열거 불가능한 속성을 정의하는 것과 어떻게 다른가요?

실제로, 숨겨 Object.keys지고 열거 될 속성을 정의하는 방법이 이미 존재했습니다 . 여기있어:

var anObject = {};
var fruit = "apple";

Object.defineProperty( anObject, fruit, {
    enumerable: false,
    value: "green"
});

어떤 차이가 Symbol()있습니까? 차이점은 Object.defineProperty일반적인 방법으로 속성을 정의 할 수 있다는 것입니다.

console.log(anObject[fruit]); //green
console.log(anObject["apple"]); //green
console.log(anObject.apple); //green

그리고 이전 단락에서와 같이 Symbol로 정의 된 경우 :

fruit = Symbol("apple");

변수를 알고있는 경우에만 값을받을 수 있습니다.

console.log(anObject[fruit]); //green
console.log(anObject["apple"]); //undefined
console.log(anObject.apple); //undefined

또한 키 아래에 다른 속성을 정의 "apple" 하면 개체가 오래된 개체를 삭제하게됩니다 (하드 코딩 된 경우 오류가 발생할 수 있음). 더 이상 사과는 없습니다! 그 유감. 이전 단락을 참조하면 기호는 고유하며 Symbol()고유하게 키를 정의합니다 .

타입 변환 및 확인

  • 다른 데이터 형식과 달리 Symbol() 합니다.

  • 호출하여 원시 데이터 유형을 기반으로 심볼을 “만들”수 있습니다 Symbol(data) .

  • 유형 확인 측면에서 아무 것도 변경되지 않습니다.

    function isSymbol ( variable ) {
        return typeof someSymbol === "symbol";
    }
    
    var a_Symbol = Symbol("hey!");
    var totally_Not_A_Symbol = "hey";
    
    console.log(isSymbol(a_Symbol)); //true
    console.log(isSymbol(totally_Not_A_Symbol)); //false


답변

내가 보는 방법은 다음과 같습니다. 심볼은 Object.keys () 및 JSON.stringify ()와 같이 널리 사용되는 일부 메서드를 통해 객체의 키 / 속성이 노출되지 않도록하여 ‘추가 수준의 개인 정보 보호’를 제공합니다.

var age = Symbol();  // declared in another module perhaps?
class Person {
   constructor(n,a){
      this.name = n;
      this[age] = a;
   }
   introduce(){
       console.log(`My name is ${this.name}. I am ${this[age]-10}.`);
   }
}
var j = new Person('Jane',45);
j.introduce();  // My name is Jane. I am 35.
console.log(JSON.stringify(j)); // {"name":"Jane"}
console.log(Object.keys(j)); // ["name"]
console.log(j[age]); // 45   (well…only if you know the age in the first place…)

객체 자체가 제공되지만 이러한 속성은 리플렉션, 프록시, Object.getOwnPropertySymbols () 등을 통해 여전히 노출 될 수 있지만 몇 가지 직접 메소드를 통해 액세스 할 수있는 자연스러운 방법은 없습니다. 때로는 OOP 관점에서 충분할 수도 있습니다.


답변

JS 심볼은 새로운 기본 데이터 유형입니다. 이것은 고유 한 ID 역할을하는 토큰입니다 . Symbol생성자를 사용하여 심볼을 만들 수 있습니다 . 예를 들어 MDN의 다음 코드를 보자.

// The symbol constructor takes one optional argument, 
// the descriptions which is used for debugging only.
// Here are two symbols with the same description
let Sym1 = Symbol("Sym");
let Sym2 = Symbol("Sym");

console.log(Sym1 == Sym2); // returns "false"
// Symbols are guaranteed to be unique.
// Even if we create many symbols with the same description,
// they are different values.

다음과 같이 심볼을 고유 한 객체 속성 키로 사용하는 것이 종종 편리합니다.

let obj = {};
let prop = Symbol();

obj[prop] = 123;  // the symbol prop is assigned 123
obj.prop  = 456;  // the string prop is assigned 456

console.log(obj.prop, obj[prop]); // logs 456, 123


답변

기호에는 두 가지 주요 사용 사례가 있습니다.

  1. “숨겨진”객체 속성. 다른 스크립트 나 라이브러리에 포함 된 객체에 속성을 추가하려는 경우 심볼을 만들어 속성 ​​키로 사용할 수 있습니다. 기호 속성은에 표시되지 않으므로 for..in실수로 다른 속성과 함께 처리되지 않습니다. 또한 다른 스크립트에는 심볼이 없으므로 직접 액세스 할 수 없습니다. 따라서이 속성은 실수로 사용하거나 덮어 쓰지 않도록 보호됩니다.

    그래서 우리는 상징적 인 속성을 사용하여 우리가 필요로하는 물체에 무언가를 숨기고 숨길 수 있습니다.

  2. 로 액세스 할 수있는 JavaScript에서 사용되는 많은 시스템 심볼이 있습니다 Symbol.*. 우리는 그것들을 사용하여 내장 동작을 변경할 수 있습니다. 예를 들어, ….
    Symbol.iteratoriterables의 경우 Symbol.toPrimitive객체 대 기본 변환 등을 설정합니다.

출처