Jaka jest motywacja do wprowadzenia symboli do ES6?

UPDATE : niedawno pojawił się genialny artykuł z Mozilli . Przeczytaj, jeśli jesteś ciekawy.

Jak zapewne wiecie, planują dodanie nowego symbolu prymitywnego typu w ECMAScript 6 (nie wspominając o innych szalonych rzeczach). Zawsze uważałem, że pojęcie :symbol W Rubim jest zbędne; zamiast tego możemy łatwo używać zwykłych łańcuchów, tak jak to robimy w JavaScript. A teraz postanawiają tym skomplikować sprawy w JS.

Nie rozumiem. motywacja. Czy ktoś mógłby mi wyjaśnić, czy naprawdę potrzebujemy symboli w JavaScript?
Author: Bergi, 2014-02-12

5 answers

Oryginalną motywacją do wprowadzenia symboli do Javascript było włączenie prywatnych właściwości.

Niestety, zostały one poważnie obniżone. Nie są już prywatne, ponieważ można je znaleźć poprzez odbicie, na przykład za pomocą Object.getOwnPropertySymbols lub proxy.

Są teraz znane jako unikalne symbole, a ich jedynym przeznaczeniem jest unikanie kolizji nazw między właściwościami. Na przykład sam ECMAScript może teraz wprowadzać Hooki rozszerzeń za pomocą pewnych metody, które można umieścić na obiektach (np. aby zdefiniować ich protokół iteracji) bez ryzyka kolizji z nazwami użytkowników.

Czy jest to wystarczająco silna motywacja do dodawania symboli do języka jest dyskusyjna.

 151
Author: Andreas Rossberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-04 05:46:51

Symbole nie gwarantują prawdziwej prywatności, ale mogą być używane do oddzielania publicznych i wewnętrznych właściwości obiektów. Weźmy przykład, gdzie możemy użyć Symbol do posiadania prywatnych własności.

Weźmy przykład, w którym własność obiektu nie jest prywatna.

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

Powyżej własność klasy Pet type nie jest prywatna. Aby uczynić to prywatnym, musimy stworzyć zamknięcie. Poniższy przykład ilustruje, jak możemy uczynić type prywatnym za pomocą zamknięcie.

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

Wada powyższego podejścia: wprowadzamy dodatkowe zamknięcie dla każdej utworzonej instancji Pet, które może zaszkodzić wydajności.

Teraz przedstawiamy Symbol. Może to pomóc nam uczynić nieruchomość prywatną bez korzystania z dodatkowych niepotrzebnych zamknięć. Przykład kodu poniżej:

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
 65
Author: Samar Panda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-19 17:06:49

Symbols są nowym, specjalnym rodzajem obiektów, które mogą być używane jako unikalna nazwa właściwości w obiektach. Użycie {[3] } zamiast string pozwala różnym modułom tworzyć właściwości, które nie są ze sobą sprzeczne. Symbols mogą być również prywatne, tak, że ich właściwości nie mogą być dostępne dla nikogo, kto nie ma już bezpośredniego dostępu do Symbol.

Symbols są nowym prymitywnym . Tak jak w number, string, i boolean prymitywy, Symbol mają funkcję, która może być używane do ich tworzenia. W przeciwieństwie do innych prymitywów, Symbols nie mają dosłownej składni (np. jak string mają '') - jedynym sposobem ich utworzenia jest użycie konstruktora Symbol w następujący sposób:

let symbol = Symbol();

W rzeczywistości, Symbol są tylko nieco innym sposobem dołączania właściwości do obiektu - możesz łatwo dostarczyć dobrze znane Symbols jako standardowe metody, tak jak Object.prototype.hasOwnProperty, które pojawiają się we wszystkim, co dziedziczy z Object.

Oto niektóre z korzyści płynących z Typ prymitywny.

Symbols mają wbudowaną debuggability

Symbols można podać opis, który jest tak naprawdę używany do debugowania, aby ułatwić życie podczas logowania ich do konsoli.

Symbols może być używany jako Object klucze

Tutaj robi się naprawdę ciekawie. Są mocno splecione z przedmiotami. Symbol mogą być przypisane jako klucze do obiektów, co oznacza, że można przypisać nieograniczoną liczbę unikalnych Symbol'S do obiektu i być gwarantuje, że nigdy nie będą one sprzeczne z string klucze, lub inne unikalne Symbols.

Symbols może być używana jako unikalna wartość.

Załóżmy, że masz bibliotekę logowania, która zawiera wiele poziomów logów, takich jak logger.levels.DEBUG, logger.levels.INFO, logger.levels.WARN i tak dalej. W kodzie ES5 należy utworzyć string s (so logger.levels.DEBUG === 'debug') lub number s (logger.levels.DEBUG === 10). Obie te wartości nie są idealne, ponieważ te wartości nie są unikalnymi wartościami, ale Symbol S są! Więc logger.levels po prostu staje się:

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

Czytaj więcej w tym Wielki artykuł.

 21
Author: Mihai Alexandru-Ionut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-05 06:57:20

Oto Jak to widzę. Symbole zapewniają "dodatkowy poziom prywatności", zapobiegając ujawnianiu kluczy/właściwości obiektu za pomocą niektórych popularnych metod, takich jak Object.keys() i 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…)

Chociaż dany obiekt sam w sobie, takie właściwości mogą być wystawione przez odbicie, proxy, obiekt.getOwnPropertySymbols () itd., nie ma naturalnych środków, aby uzyskać do nich dostęp za pomocą kilku bezpośrednich metod, które mogą być wystarczające czasami z OOP perspektywa.

 12
Author: Chong Lip Phang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-26 13:09:50

Ten post jest o Symbol(), dostarczone z rzeczywistych przykładów mogłem znaleźć/zrobić i fakty & definicje mogłem znaleźć.

TLDR;

Symbol() jest typem danych, wprowadzonym wraz z wydaniem ECMAScript 6 (ES6).

Są dwa ciekawostki o symbolu.

  • Pierwszy typ danych i jedyny typ danych w JavaScript, który nie ma literału

  • Każda zmienna, zdefiniowana za pomocą Symbol(), otrzymuje unikalną zawartość, ale nie jest tak naprawdę prywatne .

  • Wszystkie dane mają swój własny Symbol , A Dla tych samych danych symbole będą tym samym . Więcej informacji w poniższym akapicie, w przeciwnym razie nie jest to TLRD; :)

Jak zainicjować symbol?

1. Aby uzyskać unikalny identyfikator z debuggowalną wartością

Możesz to zrobić w ten sposób:

var mySymbol1 = Symbol();

Lub w ten sposób:

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

Łańcuch "some text here" nie może być wyodrębniony z symbolu, to tylko opis do celów debugowania. Nie zmienia to w żaden sposób zachowania symbolu. Chociaż możesz console.log to (co jest sprawiedliwe, ponieważ wartość jest do debugowania, aby nie pomylić tego dziennika z innym wpisem dziennika):

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

2. Aby uzyskać symbol dla niektórych danych łańcuchowych

W tym przypadku wartość symbolu wynosi W rzeczywistości i w ten sposób dwa symbole mogą być niepowtarzalne.

var a1 = Symbol.for("test");
var a2 = Symbol.for("test");
console.log(a1 == a2); //true!
Nazwijmy te symbole" symbolami drugiego typu". Nie przecinają się one w żaden sposób z symbolami "pierwszego typu" (tj. tymi zdefiniowanymi za pomocą Symbol(data)).

Następne dwa akapity dotyczą tylko symbolu pierwszego typu .

Jak mogę skorzystać z używania symbolu zamiast starszych typów danych?

Rozważmy najpierw obiekt, standardowy typ danych. Możemy tam zdefiniować kilka par klucz-wartości i mieć dostęp do wartości poprzez podanie klucza.

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

Co jeśli mamy dwie osoby o nazwisku Peter?

Robi to:

var persons = {"peter":"first", "peter":"pan"};
To nie miałoby sensu. Wygląda na to, że jest problem dwóch zupełnie różnych osób o tym samym imieniu. Odnieśmy się zatem do nowego Symbol(). To jest jak osoba w prawdziwym życiu-każda osoba jest wyjątkowa , ale ich imiona mogą być równe. Zdefiniujmy dwie osoby.
 var a = Symbol("peter");
 var b = Symbol("peter");
Teraz mamy dwie różne osoby o tym samym imieniu. Czy nasze osoby naprawdę się różnią? Są, możesz sprawdzić to:
 console.log(a == b);
 // false

Jak na tym zyskamy?

Możemy zrobić dwa wpisy w Twoim obiekcie dla różnych osób i nie można ich w żaden sposób pomylić.

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

Uwaga:
Warto jednak zauważyć, że stringowanie obiektu JSON.stringify spowoduje upuszczenie wszystkich par inicjowanych symbolem jako kluczem.
Wykonanie Object.keys nie zwróci takich Symbol()->value par.

Użycie tej inicjalizacji jest absolutnie niemożliwe pomylić wpisy z pierwszą i drugą osobą. Wywołanie console.log dla nich poprawnie wyświetli ich drugie imiona.

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

Kiedy jest używana w obiekcie, czym różni się od definicji nieliczalnej właściwości?

Rzeczywiście, istniał już sposób na zdefiniowanie właściwości, która ma być ukryta przed Object.keys i wyliczenie. Oto ona:

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

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

Co to za różnica? Różnica polega na tym, że nadal można uzyskać Właściwość zdefiniowaną za pomocą Object.defineProperty w zwykły sposób:

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

I jeśli zdefiniowano symbolem jak w poprzednim akapicie:

fruit = Symbol("apple");

Będziesz miał możliwość otrzymania jego wartości tylko wtedy, gdy znasz jego zmienną, tj.

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

Ponadto, zdefiniowanie innej właściwości pod kluczem "apple" spowoduje, że obiekt upuści starszą (i jeśli zostanie zakodowany na twardo, może spowodować błąd). Koniec z jabłkami! Szkoda. Odwołując się do poprzedniego akapitu, symbole są unikalne i zdefiniowanie klucza jako Symbol() sprawi, że wyjątkowe.

Konwersja i sprawdzanie typu

  • W przeciwieństwie do innych typów danych, nie można przekonwertować Symbol() na inny typ danych.

  • Możliwe jest "stworzenie" symbolu na podstawie prymitywnego typu danych przez wywołanie Symbol(data).

  • Jeśli chodzi o sprawdzanie typu, nic się nie zmienia.

    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
    

 11
Author: nicael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-04 04:39:28