Maison > Article > interface Web > Compréhension approfondie de la façon d'utiliser Symbol dans JavaScript_Basic knowledge
Qu'est-ce que le symbole ?
Les symboles ne sont pas des icônes et ne signifient pas non plus que de petites images peuvent être utilisées dans le code :
n'est pas non plus une syntaxe pour faire référence à autre chose. Alors, qu’est-ce que Symbole exactement ?
Sept types de données
Lorsque JavaScript a été standardisé en 1997, il existait 6 types de données. Jusqu'à l'avènement d'ES6, les variables du programme devaient être l'un des 6 types de données suivants :
Indéfini
Nul
Booléen
Numéro
Chaîne
Objet
Chaque type de données est une combinaison d'une série de valeurs, et le nombre de valeurs des cinq premiers types de données est limité. Le type booléen n'a que deux valeurs : vrai et faux Lors de l'affectation d'une valeur à une variable de type booléen, aucune nouvelle valeur n'est générée (les deux valeurs vrai et faux sont partagées). Pour Number et String, leurs valeurs sont bien plus. L'instruction standard est qu'il existe 18 437 736 874 454 810 627 valeurs de type Number (y compris NAN). Le nombre de types String est difficile à compter. Au départ, je pensais que c'était (2144,115,188,075,855,872 ? 1) ÷ 65,535... mais j'avais peut-être tort.
Le nombre de valeurs d'objet est illimité et chaque objet est unique. Chaque fois qu'une page Web est ouverte, une série d'objets est créée.
Le symbole dans ES6 est aussi un type de données, mais ce n'est pas une chaîne ou un objet, mais un nouveau type de données : le septième type de données.
Regardons un scénario dans lequel Symbol peut s'avérer utile.
Une question soulevée par une valeur booléenne
Parfois, il est très pratique de stocker temporairement certaines données appartenant à d'autres objets dans un autre objet. Par exemple, supposons que vous écriviez une bibliothèque JS qui utilise des transitions en CSS pour faire voler un élément DOM sur l'écran. Vous savez déjà que vous ne pouvez pas appliquer plusieurs transitions au même div en même temps, sinon l'animation sera très disgracieuse. . Vous avez un moyen de contourner ce problème, mais vous devez d'abord savoir si le div bouge déjà.
Comment résoudre ce problème ?
Une solution consiste à utiliser l'API fournie par le navigateur pour détecter si l'élément est dans un état animé, mais c'est une perte de temps. Lorsque vous configurez l'élément pour qu'il se déplace, votre bibliothèque sait que l'élément se déplace.
Ce dont vous avez vraiment besoin, c'est d'un mécanisme pour garder une trace des éléments en mouvement, vous pouvez enregistrer les éléments en mouvement dans un tableau, et chaque fois que vous souhaitez animer un élément, vérifiez d'abord si l'élément est déjà dans celui-ci. dans la liste.
Ahem, mais si votre tableau est très grand, même une recherche linéaire comme celle-ci peut créer des problèmes de performances.
Donc, ce que vous voulez vraiment faire, c'est définir un indicateur directement sur l'élément :
if (element.isMoving) { smoothAnimations(element); } element.isMoving = true; if (element.isMoving) { smoothAnimations(element); } element.isMoving = true;
Cela présente également des problèmes potentiels, et vous devez reconnaître le fait qu'il existe un autre code qui peut également fonctionner sur cet élément ODM.
if (element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__) { smoothAnimations(element); } element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__ = true; if (element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__) { smoothAnimations(element); } element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__ = true;
Vous pouvez également utiliser des algorithmes de chiffrement pour générer une chaîne presque unique :
// get 1024 Unicode characters of gibberish var isMoving = SecureRandom.generateName(); ... if (element[isMoving]) { smoothAnimations(element); } element[isMoving] = true; // get 1024 Unicode characters of gibberish var isMoving = SecureRandom.generateName(); ... if (element[isMoving]) { smoothAnimations(element); } element[isMoving] = true;La syntaxe
Cependant, cela conduit à une mauvaise expérience de débogage. Chaque fois que vous utilisez console.log() pour imprimer l'élément contenant cet attribut, vous verrez une énorme chaîne inutile, et que se passe-t-il s'il existe plusieurs de ces attributs ? ? Les noms des attributs ont changé après chaque actualisation. Comment rendre ces attributs plus intuitifs ?
Pourquoi est-ce si difficile ? Nous économisons juste un petit peu de drapeau.
Utilisez Symbol pour résoudre des problèmes
var mySymbol = Symbol(); var mySymbol = Symbol();
调用 Symbol() 方法将创建一个新的 Symbol 类型的值,并且该值不与其它任何值相等。
与数字和字符串一样,Symbol 类型的值也可以作为对象的属性名,正是由于它不与任何其它值相等,对应的属性也不会发生冲突:
obj[mySymbol] = "ok!"; // guaranteed not to collide console.log(obj[mySymbol]); // ok! obj[mySymbol] = "ok!"; // guaranteed not to collide console.log(obj[mySymbol]); // ok!
下面是使用 Symbol 来解决上面的问题:
// create a unique symbol var isMoving = Symbol("isMoving"); ... if (element[isMoving]) { smoothAnimations(element); } element[isMoving] = true; // create a unique symbol var isMoving = Symbol("isMoving"); ... if (element[isMoving]) { smoothAnimations(element); } element[isMoving] = true;
上面代码需要注意几点:
由于 Symbol 的设计初衷是为了避免冲突,当遍历 JavaScript 对象时,并不会枚举到以 Symbol 作为建的属性,比如,for-in 循环只会遍历到以字符串作为键的属性,Object.keys(obj)和 Object.getOwnPropertyNames(obj) 也一样,但这并不意味着 Symbol 为键的属性是不可枚举的:使用 Object.getOwnPropertySymbols(obj) 这个新方法可以枚举出来,还有 Reflect.ownKeys(obj) 这个新方法可以返回对象中所有字符串和 Symbol 键。(我将在后面的文章中详细介绍 Reflect 这个新特性。)
库和框架的设计者将会发现很多 Symbol 的用途,稍后我们将看到,JavaScript 语言本身也对其有广泛的应用。
Symbol 究竟是什么呢
> typeof Symbol() "symbol" > typeof Symbol() "symbol"
Symbol 是完全不一样的东西。一旦创建后就不可更改,不能对它们设置属性(如果在严格模式下尝试这样做,你将得到一个 TypeError)。它们可以作为属性名,这时它们和字符串的属性名没有什么区别。
另一方面,每个 Symbol 都是独一无二的,不与其它 Symbol 重复(即便是使用相同的 Symbol 描述创建),创建一个 Symbol 就跟创建一个对象一样方便。
ES6 中的 Symbol 与传统语言(如 Lisp 和 Ruby)中的 Symbol 中的类似,但并不是完全照搬到 JavaScript 中。在 Lisp 中,所有标识符都是 Symbol;在 JavaScript 中,标识符和大多数属性仍然是字符串,Symbol 只是提供了一个额外的选择。
值得注意的是:与其它类型不同的是,Symbol 不能自动被转换为字符串,当尝试将一个 Symbol 强制转换为字符串时,将返回一个 TypeError。
> var sym = Symbol("<3"); > "your symbol is " + sym // TypeError: can't convert symbol to string > `your symbol is ${sym}` // TypeError: can't convert symbol to string > var sym = Symbol("<3"); > "your symbol is " + sym // TypeError: can't convert symbol to string > `your symbol is ${sym}` // TypeError: can't convert symbol to string
Une telle coercition doit être évitée et String(sym) ou sym.toString() doit être utilisé pour la conversion.
Trois façons d'obtenir le symbole
Si vous n'êtes toujours pas sûr de l'utilité des symboles, la section suivante sera très intéressante car je vais vous montrer les symboles en action.
Application du symbole dans la spécification ES6
Nous savons déjà que nous pouvons utiliser Symbol pour éviter les conflits de code. Lors de l'introduction de l'itérateur auparavant, nous avons également analysé que for (var item of myArray) commence en interne par l'appel de myArray[Symbol.iterator](). À cette époque, j'ai mentionné que cette méthode pouvait être remplacée par myArray.iterator(), mais en utilisant. Le symbole a une meilleure compatibilité ascendante.
Il existe encore des endroits où Symbol est utilisé dans ES6. (Ces fonctionnalités ne sont pas encore implémentées dans FireFox.)
Ces usages sont encore relativement restreints, mais il est difficile de voir l'impact significatif de ces nouvelles fonctionnalités rien qu'en regardant le code de mon article. Le symbole JavaScript est une version améliorée de __doubleUnderscores en PHP et Python, et les organismes de normalisation l'utiliseront pour ajouter de nouvelles fonctionnalités au langage sans affecter le code existant.