UPDATE: Récemment, un article brillant de Mozilla est apparu. Lisez-le si vous êtes curieux.
Comme vous le savez peut-être, ils sont prévoient d'inclure le nouveau type de primitive Symbol dans ECMAScript 6 (sans oublier quelques autres trucs fous). J'ai toujours pensé que la notion de :symbol
dans Ruby était inutile; nous pourrions facilement utiliser des chaînes simples à la place, comme nous le faisons en JavaScript. Et maintenant, ils décident de compliquer les choses avec JS.
Je ne comprends pas la motivation. Quelqu'un pourrait-il m'expliquer si nous avons réellement besoin de symboles en JavaScript?
La motivation initiale pour l'introduction de symboles dans Javascript était d'activer les propriétés privées.
Malheureusement, ils ont fini par être sévèrement dégradés. Ils ne sont plus privés, car vous pouvez les trouver via la réflexion, par exemple, en utilisant Object.getOwnPropertySymbols
ou des proxies.
Ils sont maintenant appelés symboles niques et leur seule utilisation est d'éviter les conflits de noms entre propriétés. Par exemple, ECMAScript lui-même peut désormais introduire des points d’extension via certaines méthodes que vous pouvez appliquer à des objets (par exemple, pour définir leur protocole d’itération) sans risquer de les heurter avec des noms d’utilisateur.
La motivation pour ajouter des symboles à la langue est assez discutable.
Les symboles ne garantissent pas une véritable confidentialité, mais peuvent être utilisés pour séparer les propriétés publiques et internes des objets. Prenons un exemple où nous pouvons utiliser Symbol
pour avoir des propriétés privées.
Prenons un exemple où une propriété d'un objet n'est pas privée.
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
Ci-dessus, la propriété de classe Pet
type
n'est pas privée. Pour le rendre privé, nous devons créer une fermeture. L'exemple ci-dessous montre comment rendre type
privé en utilisant une fermeture.
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
Inconvénient de l'approche ci-dessus: nous introduisons une fermeture supplémentaire pour chaque instance Pet
créée, ce qui peut nuire aux performances.
Maintenant nous introduisons Symbol
. Cela peut nous aider à rendre une propriété privée sans utiliser de fermetures inutiles. Exemple de code ci-dessous:
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
est un nouveau type d'objet spécial qui peut être utilisé comme nom de propriété unique dans les objets. Utiliser Symbol
au lieu de string
permet à différents modules de créer des propriétés qui ne sont pas en conflit les unes avec les autres. Symbols
peut également être rendu privé, de sorte que leurs propriétés ne sont pas accessibles aux personnes n'ayant pas déjà un accès direct à Symbol
.
Symbols
sont une nouvelle primitive . Tout comme les primitives number
, string
et boolean
, Symbol
ont une fonction qui peut être utilisée pour les créer. Contrairement aux autres primitives, Symbols
n'a pas de syntaxe littérale (par exemple, comment string
ont ''
) - le seul moyen de les créer consiste à utiliser le constructeur Symbol
de la manière suivante:
let symbol = Symbol();
En réalité, Symbol
n'est qu'une manière légèrement différente d'attacher des propriétés à un objet - vous pouvez facilement fournir le nom connu Symbols
en tant que méthodes standard, tout comme Object.prototype.hasOwnProperty
qui figure dans tout ce qui hérite de Object
.
Voici certains des avantages du type primitif Symbol
.
Symbols
ont une capacité de débogage intégréeIl est possible de donner à Symbols
une description, qui est en réalité simplement utilisée pour le débogage afin de faciliter la vie lorsque vous les enregistrez sur une console.
Symbols
peut être utilisé comme Object
C'est là que Symbol
devient vraiment intéressant. Ils sont fortement liés aux objets. Symbol
peut être affecté en tant que clés à des objets, ce qui signifie que vous pouvez affecter un nombre illimité de Symbol
uniques à un objet et être assuré que ceux-ci ne seront jamais en conflit avec string
ou à un autre Symbols
unique.
Symbols
peut être utilisé comme valeur unique.Supposons que vous disposiez d’une bibliothèque de journalisation comprenant plusieurs niveaux de journalisation, tels que logger.levels.DEBUG
, logger.levels.INFO
, logger.levels.WARN
, etc. Dans le code ES5, vous voudriez créer ces string
s (donc logger.levels.DEBUG === 'debug'
), ou number
s (logger.levels.DEBUG === 10
). Ces deux valeurs ne sont pas idéales car ces valeurs ne sont pas des valeurs uniques, mais Symbol
s le sont! Donc, logger.levels
devient simplement:
log.levels = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn'),
};
log(log.levels.DEBUG, 'debug message');
log(log.levels.INFO, 'info message');
Lire la suite dans ce excellent article.
Cet article concerne la Symbol()
, avec des exemples concrets que je pourrais trouver/faire et des faits et définitions que je pourrais trouver.
La Symbol()
est le type de données introduit avec la version ECMAScript 6 (ES6).
Il y a deux faits curieux sur le symbole.
le premier type de données et seul type de données en JavaScript qui n'a pas de littéral
toute variable, définie avec Symbol()
, obtient un contenu unique, mais ce n'est pas vraiment privé .
toute donnée a son symbole propre , et pour les mêmes données, les symboles seraient identiques . Plus d'informations dans le paragraphe suivant, sinon ce n'est pas un TLRD; :)
Vous pouvez le faire soit de cette façon:
var mySymbol1 = Symbol();
Ou de cette façon:
var mySymbol2 = Symbol("some text here");
La chaîne "some text here"
ne peut pas être extraite du symbole, il s'agit simplement d'une description à des fins de débogage. Cela ne change en rien le comportement du symbole. Bien que vous puissiez console.log
le (ce qui est juste, puisque la valeur est pour le débogage, afin de ne pas confondre ce journal avec une autre entrée de journal):
console.log(mySymbol2);
// Symbol(some text here)
Dans ce cas, la valeur du symbole est réellement prise en compte et ainsi deux symboles peuvent être non uniques.
var a1 = Symbol.for("test");
var a2 = Symbol.for("test");
console.log(a1 == a2); //true!
Appelons ces symboles des symboles "de second type". Ils ne se croisent pas avec les symboles du "premier type" (c'est-à-dire ceux définis avec Symbol(data)
) de quelque manière que ce soit.
Les deux paragraphes suivants concernent uniquement le symbole de premier type .
Considérons d’abord un objet, un type de données standard. Nous pourrions définir certaines paires clé-valeur et avoir un accès aux valeurs en spécifiant la clé.
var persons = {"peter":"pan","jon":"doe"};
console.log(persons.peter);
// pan
Et si nous avons deux personnes avec le nom de Peter?
Ce faisant:
var persons = {"peter":"first", "peter":"pan"};
ça n'aurait pas beaucoup de sens.
Donc, semble être un problème de deux personnes absolument différentes ayant le même nom. Faisons ensuite référence à la nouvelle Symbol()
. C'est comme une personne dans la vie réelle - chaque personne est unique , mais leurs noms peuvent être égaux. Définissons deux "personnes".
var a = Symbol("peter");
var b = Symbol("peter");
Nous avons maintenant deux personnes différentes portant le même nom. Nos personnes sont-elles vraiment différentes? Elles sont; vous pouvez vérifier ceci:
console.log(a == b);
// false
Comment en profitons-nous?
Nous pouvons faire deux entrées dans votre objet pour les différentes personnes et elles ne peuvent en aucun cas être confondues.
var firstPerson = Symbol("peter");
var secondPerson = Symbol("peter");
var persons = {[firstPerson]:"first", [secondPerson]:"pan"};
Remarque:
Toutefois, il convient de noter que le fait de chaîner l'objet avecJSON.stringify
supprimera toutes les paires initialisées avec un symbole comme clé.
L'exécution deObject.keys
ne renverra pas non plus de telles pairesSymbol()->value
.
Avec cette initialisation, il est absolument impossible de confondre les entrées pour la première et la deuxième personne. Si vous appelez console.log
pour eux, leur deuxième nom sera correctement affiché.
console.log(persons[a]);
// first
console.log(persons[b]);
// pan
En effet, il existait déjà un moyen de définir une propriété à masquer de Object.keys
et d’énumérer. C'est ici:
var anObject = {};
var fruit = "Apple";
Object.defineProperty( anObject, fruit, {
enumerable: false,
value: "green"
});
Quelle différence Symbol()
y apporte-t-il? La différence est que vous pouvez toujours obtenir la propriété définie avec Object.defineProperty
de la manière habituelle:
console.log(anObject[fruit]); //green
console.log(anObject["Apple"]); //green
console.log(anObject.Apple); //green
Et si défini avec Symbol comme dans le paragraphe précédent:
fruit = Symbol("Apple");
Vous ne pourrez recevoir sa valeur que si vous connaissez sa variable, c.-à-d.
console.log(anObject[fruit]); //green
console.log(anObject["Apple"]); //undefined
console.log(anObject.Apple); //undefined
De plus, la définition d’une autre propriété sous la clé "Apple"
fera que l’objet supprime l’ancienne (et, s’il est codé en dur, il pourrait générer une erreur). Donc, plus de pommes! C'est dommage. En se référant au paragraphe précédent, les symboles sont uniques et définir une clé comme Symbol()
le rendra unique.
Contrairement aux autres types de données, il est impossible de convertir Symbol()
en un autre type de données.
Il est possible de "créer" un symbole basé sur un type de données primitif en appelant Symbol(data)
.
En termes de vérification du type, rien ne change.
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
Voici comment je le vois. Les symboles fournissent un "niveau supplémentaire de confidentialité" en empêchant les clés/propriétés d'un objet d'être exposées par le biais de méthodes courantes telles que Object.keys () et 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…)
Bien qu’il soit donné à un objet en soi, de telles propriétés peuvent toujours être exposées par réflexion, proxy, Object.getOwnPropertySymbols (), etc., il n’existe aucun moyen naturel d’y accéder par quelques méthodes directes, qui peuvent parfois suffire à partir de OOP perspective.
Un symbole JS est un nouveau type de données primitif. Ce sont des jetons qui servent d'identifiants uniques. Un symbole peut être créé à l'aide du constructeur Symbol
. Prenez par exemple cet extrait de 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.
Il est souvent utile d’utiliser des symboles en tant que clés uniques de propriétés d’objet, par exemple:
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