La sécurité est un problème qui ne doit pas être pris à la légère. Les programmeurs novices peuvent ne pas être familiarisés avec certaines de ces techniques de sécurité JavaScript, e incluso uno que otro programmeur experimentado puede que también ignore estas prácticas. Sin embargo, mas allá de la importancia de conocer estos métodos es praticarlos día a día en nuestra programmation.
Les propriétés du projet étaient traditionnellement laissées sans protection dans JavaScript ou masquées, capturées dans une fermeture. Les symboles et les WeakMaps offrent une autre alternative.
Chrome (version 36) et Firefox (version 31) prennent en charge WeakMaps. Chrome 36 prend en charge les symboles, mais vous devez activer JavaScript expérimental dans chrome://flags/#enable-javascript-harmony. Firefox prend en charge les symboles de la version 33.
Scénario non protégé
Instances de personne créé à l'aide de la fonction ci-dessous aura des propriétés stockées directement en eux.
var Person = (function () {function Person (name) {this.name = name;} Person.prototype.getName = function () {return this.name;}; return Person;} ()); var p = nouvelle personne ('Jean'); print ('Nom de la personne 1:' + p.getName ()); supprimer p.name; print ('Nom de la personne 1:' + p.getName () + '- modifié à l'extérieur.');
Cette approche a l'avantage que tous instances de la personne ils sont similaires et l'accès aux propriétés de ces instances peut être optimisé. Mais d'un autre côté, il n'y a pas de propriétés privées ici - toutes les propriétés de l'objet peuvent être modifiées par code externe (dans ce cas - supprimé).
Plusieurs bibliothèques préfèrent préfixer les propriétés destinées à être privées avec le trait de soulignement (par exemple, _nom).
Autres - comme TypeScript - dependen del compilador para marcar todos los usos ilegales de una propiedad privada.
Masquer les propriétés avec des fermetures
Pour isoler une propriété d'une modification externe, vous pouvez utiliser une fermeture interne qui se ferme sur le Nom de variable. Les conventions de code Douglas Crockford pour JavaScript recommandent ce modèle lorsque la confidentialité est importante pour dissuader les propriétés des noms avec le préfixe de soulignement pour indiquer la confidentialité.
var Person = (function () {function Person (name) {this.getName = function () {return name;};} return Person;} ()); var p = nouvelle personne ('Jean'); print ('Nom de la personne 2:' + p.getName ()); supprimer p.name; print ('Nom de la personne 2:' + p.getName () + 'reste privé.');
L'approche de fermeture a l'avantage d'une vraie confidentialité, mais le coût est que pour chaque instance de Person, une nouvelle fermeture doit être créée (la fonction dans le constructeur du Personne).
Utilisation de symboles
Avec ES6, il existe une autre façon de stocker les propriétés: les symboles.
Les symboles sont similaires aux noms privés mais - contrairement aux noms privés - ils n'offrent pas une véritable confidentialité.
Para ejecutar el ejemplo que ves tu le navigateur debe soportar:
var Person = (function () {var nameSymbol = Symbol ('name'); function Person (name) {this [nameSymbol] = name;} Person.prototype.getName = function () {return this [nameSymbol];}; return Person;} ()); var p = nouvelle personne ('Jean'); print ('Nom de la personne 3:' + p.getName ()); supprimer p.name; print ('Nom de la personne 3:' + p.getName () + '- reste privé.'); print ('Propriétés de la personne 3:' + Object.getOwnPropertyNames (p));
Les symboles n'augmentent pas le nombre de fermetures pour chaque instance créée. Il n'y a qu'un seul fermoir pour protéger le symbole.
Les symboles sont utilisés pour indexer les objets JavaScript. La principale différence avec les autres types est qu'ils ne sont pas convertis en chaînes et exposés par Object.getOwnPropertyNames. Ce n'est qu'en utilisant le symbole de référence que vous pouvez définir et récupérer des valeurs de l'objet. Une liste des symboles attribués à un objet donné est accessible avec la fonction Object.getOwnPropertySymbols.
Chaque symbole est unique, même s'il a été créé avec la même étiquette.
Symboles ES6 ✅
var sym1 = Symbole ('a'); var sym2 = Symbole ('b'); var sym3 = Symbole ('a'); print ('sym1 === sym1:' + (sym1 === sym1)); print ('sym1 === sym2:' + (sym1 === sym2)); print ('sym1 === sym3:' + (sym1 === sym3));
Les symboles présentent les inconvénients suivants:
- Une plus grande complexité dans la gestion des symboles - au lieu d'un simple p.name, vous devez d'abord obtenir la référence du symbole, puis utiliser p [nomSymbole].
- Actualmente sólo unos pocos navigateurs soportan símbolos.
- No garantizan una verdadera privacidad, pero pueden utilizarse para separar las propiedades públicas de las internas de los objetos. Es similar a cómo la mayoría de los lenguajes orientados a objetos permiten el acceso a propiedades privadas a través de la API de reflexión.
Les symboles privés sont toujours pris en compte pour ECMAScript, mais l'implémentation correcte qui ne filtre jamais les symboles est difficile. Les symboles privés sont déjà utilisés par la spécification ES6 et implémentés en interne dans V8.
Utilisation de WeakMaps
Une autre approche pour stocker les propriétés privées est WeakMaps.
Une instance WeakMap est masquée dans une fermeture et est indexée par des instances de personne. Les valeurs de mappage sont des objets qui contiennent des données privées.
var Person = (function () {var private = new WeakMap (); function Person (name) {var privateProperties = {name: name}; private.set (this, privateProperties);} Person.prototype.getName = function () {return private.get (this) .name;}; return Person;} ()); var p = nouvelle personne ('Jean'); print ('Nom de la personne 4:' + p.getName ()); supprimer p.name; print ('Nom de la personne 4:' + p.getName () + '- reste privé.'); print ('Propriétés de la personne 4:' + Object.getOwnPropertyNames (p));
Il est possible d'utiliser Map au lieu d'un WeakMap ou même de quelques tableaux pour imiter cette solution. Mais l'utilisation de WeakMap présente un avantage significatif: elle permet aux instances Person d'être récupérées.
Une carte ou une matrice contient des objets qui contiennent fortement. Personne c'est une fermeture qui capture la variable privée - qui est également une référence forte. Le garbage collector peut collecter un objet s'il n'y a que des références faibles à celui-ci (ou s'il n'y a aucune référence du tout). En raison des deux références fortes, tant que la fonction Personne être alcanzable desde las raíces de la CG, entonces cada instancia de Person jamás creada es alcanzable y por lo tanto no puede ser recolectada como basura.
Le WeakMap détient les clés faiblement et cela rend à la fois l'instance Person et ses données privées éligibles pour le garbage collection lorsqu'un objet Personne Il n'est plus référencé par le reste de l'application.
Accès aux propriétés d'autres instances
Toutes les solutions présentées (à l'exception des fermetures) ont une caractéristique intéressante. Les instances peuvent accéder aux propriétés privées d'autres instances.
L'exemple suivant classe les instances de Personne par leurs noms. La fonction comparer aux utilise les données privées de cette instance et d'autres.
var Person = (function () {var private = new WeakMap (); function Person (name) {var privateProperties = {name: name}; private.set (this, privateProperties);} Person.prototype.compareTo = function (autre ) {var thisName = private.get (this) .name; var otherName = private.get (other) .name; return thisName.localeCompare (otherName);}; Person.prototype.toString = function () {return private.get (this) .name;}; return Person;} ()); var people = [nouvelle personne ('John'), nouvelle personne ('Jane'), nouvelle personne ('Jim')]; people.sort (function (first, second) {return first.compareTo (second);}); print ('Personnes triées:' + people.join (','));
Le même exemple écrit en Java:
import java.util.Arrays; classe Person implémente Comparable {nom de chaîne privé; Public Person (String name) {this.name = name; } public int compareTo (Personne autre) {return this.name.compareTo (autre.nom); } chaîne publique toString () {return this.name; }} classe publique Main {public static final void main (String ... args) {Person [] people = new Person [] {new Person ("John"), new Person ("Jane"), new Person ("Jim ")}; Arrays.sort (personnes); System.out.print ("Personnes triées:" + Arrays.toString (personnes)); }}
La méthode Personne :: compareTo utilise le nom de champ privé de cette instance et d'un autre objet.
Felicidades por haber finalizado este nuevo tutorial, recuerda que en tu la toile schoolJavaScript.com tendrás acceso a los mejores cursos de langage de programmation JavaScript.