Maison >interface Web >js tutoriel >Exemple de code montrant comment intégrer des membres privés dans des objets JavaScript (image)
Récemment, j'ai développé un projet Angular Cloud Data Connector pour aider les développeurs Angular à utiliser les données cloud, notamment les services mobiles Azure, en utilisant les standards WEB, tels que la base de données indexée. J'essaie de créer un moyen permettant aux développeurs JavaScript d'intégrer des membres privés dans un objet.
Ma technique pour résoudre ce problème utilise ce que j'ai nommé l'espace fermeture. Dans cet article d'introduction, je souhaite partager comment l'utiliser dans vos projets et son impact sur les performances et la mémoire dans les principaux navigateurs.
Avant d'étudier en profondeur, parlons d'abord des raisons pour lesquelles vous devez utiliser des membres privés, et il existe une autre manière de simuler des membres privés.
Si vous souhaitez commenter cet article, n'hésitez pas à me tweeter : @deltakosh.
Lorsque vous créez un objet en JavaScript, vous pouvez déclarer des membres de valeur. Si vous envisagez d'en contrôler l'accès en lecture/écriture, vous pouvez le déclarer comme suit :
var entity = {}; entity._property = "hello world"; Object.defineProperty(entity, "property", { get: function () { return this._property; }, set: function (value) { this._property = value; }, enumerable: true, configurable: true });
De cette façon, vous avez un contrôle total sur les opérations de lecture et d'écriture. Le problème est que le membre _property est toujours accessible et modifié directement.
C'est pourquoi nous avons besoin d'un moyen plus stable et fiable de déclarer les membres privés, accessibles via des méthodes objet.
La solution est d'utiliser l'espace de fermeture. Chaque fois qu'une fonction interne accède à une variable depuis la portée de la fonction externe, le navigateur vous alloue un espace mémoire. Parfois, c'est délicat, mais pour notre problème, c'est une solution parfaite.
我们在上个代码版本中添加这个特性: var createProperty = function (obj, prop, currentValue) { Object.defineProperty(obj, prop, { get: function () { return currentValue; }, set: function (value) { currentValue = value; }, enumerable: true, configurable: true }); } var entity = {}; var myVar = "hello world";createProperty(entity, "property", myVar);
Dans l'exemple, la fonction createProperty a une variable currentValue, et il existe des méthodes get et set. Cette variable est enregistrée dans l'espace de fermeture des fonctions get et set. Désormais, seules ces deux fonctions peuvent voir et mettre à jour la variable currentValue ! Mission accomplie
Le seul bémol, avertissement, attention) est que la valeur source (myVar) est toujours accessible ! Une autre version plus robuste (protégeant la variable myVar) est donnée ci-dessous :
var createProperty = function (obj, prop) { var currentValue = obj[prop]; Object.defineProperty(obj, prop, { get: function () { return currentValue; }, set: function (value) { currentValue = value; }, enumerable: true, configurable: true }); } var entity = { property: "hello world" }; createProperty(entity, "property");
En utilisant cette fonction, même les valeurs sourcessont détruites (détruites, attention : cela signifie qu'elles ne peuvent pas être affectées directement ). Vous avez terminé !
Regardons maintenant les performances.
Évidemment, comparé à une simple variable, un espace de fermeture ou même une propriété (d'objet), il est beaucoup plus lent et plus gourmand en ressources. C’est pourquoi cet article se concentre davantage sur les différences entre les méthodes ordinaires et les mécanismes d’espace de fermeture.
Pour prouver que le mécanisme de fermeture de l'espace ne consomme pas plus de ressources que la méthode standard, j'ai écrit le code suivant pour un test de référence :
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <style> html { font-family: "Helvetica Neue", Helvetica; } </style> <body> <p id="results">Computing...</p> <script> var results = document.getElementById("results"); var sampleSize = 1000000; var opCounts = 1000000; var entities = []; setTimeout(function () { // Creating entities for (var index = 0; index < sampleSize; index++) { entities.push({ property: "hello world (" + index + ")" }); } // Random reads var start = new Date().getTime(); for (index = 0; index < opCounts; index++) { var position = Math.floor(Math.random() * entities.length); var temp = entities[position].property; } var end = new Date().getTime(); results.innerHTML = "<strong>Results:</strong><br>Using member access: <strong>" + (end - start) + "</strong> ms"; }, 0); setTimeout(function () { // Closure space ======================================= var createProperty = function (obj, prop, currentValue) { Object.defineProperty(obj, prop, { get: function () { return currentValue; }, set: function (value) { currentValue = value; }, enumerable: true, configurable: true }); } // Adding property and using closure space to save private value for (var index = 0; index < sampleSize; index++) { var entity = entities[index]; var currentValue = entity.property; createProperty(entity, "property", currentValue); } // Random reads var start = new Date().getTime(); for (index = 0; index < opCounts; index++) { var position = Math.floor(Math.random() * entities.length); var temp = entities[position].property; } var end = new Date().getTime(); results.innerHTML += "<br>Using closure space: <strong>" + (end - start) + "</strong> ms"; }, 0); setTimeout(function () { // Using local member ======================================= // Adding property and using local member to save private value for (var index = 0; index < sampleSize; index++) { var entity = entities[index]; entity._property = entity.property; Object.defineProperty(entity, "property", { get: function () { return this._property; }, set: function (value) { this._property = value; }, enumerable: true, configurable: true }); } // Random reads var start = new Date().getTime(); for (index = 0; index < opCounts; index++) { var position = Math.floor(Math.random() * entities.length); var temp = entities[position].property; } var end = new Date().getTime(); results.innerHTML += "<br>Using local member: <strong>" + (end - start) + "</strong> ms"; }, 0); </script> </body> </html>
J'ai créé un million d'objets, tous quels membres de la propriété. Pour réaliser les trois tests suivants :
Effectuez 1 million d'accès aléatoires aux attributs.
Effectue 1 million de versions d'implémentation d'espace de fermeture à accès aléatoire.
Effectue 1 million d'accès aléatoires à l'implémentation get/set régulière.
Les résultats des tests sont présentés dans les tableaux et graphiques suivants :
Nous avons constaté que la mise en œuvre de l'espace de fermeture est toujours plus rapide que la mise en œuvre conventionnelle, en fonction du navigateur, peut également apporter d'autres optimisations de performances.
Les performances sur Chrome sont inférieures aux attentes. Il y a peut-être un bug, donc pour confirmer, j'ai contacté l'équipe du projet Google et décrit les symptômes survenus. De plus, si vous souhaitez tester les performances de Microsoft Edge, le nouveau navigateur de Microsoft installé par défaut dans Windows 10, vous pouvez cliquer pour télécharger le fichier .
Cependant, si vous étudiez attentivement, vous constaterez que l'utilisation de l'espace ou des attributs de fermeture prend environ 10 fois plus de temps que l'accès direct aux membres variables. Par conséquent, utilisez-le de manière appropriée et avec prudence.
Il faut également vérifier que cette technologie ne consomme pas trop de mémoire. Pour tester le benchmark d'utilisation de la mémoire, j'ai écrit l'extrait de code suivant :
var sampleSize = 1000000; var entities = []; // Creating entities for (var index = 0; index < sampleSize; index++) { entities.push({ property: "hello world (" + index + ")" });}
var sampleSize = 1000000; var entities = []; // Adding property and using local member to save private value for (var index = 0; index < sampleSize; index++) { var entity = {}; entity._property = "hello world (" + index + ")"; Object.defineProperty(entity, "property", { get: function () { return this._property; }, set: function (value) { this._property = value; }, enumerable: true, configurable: true }); entities.push(entity); }
var sampleSize = 1000000; var entities = []; var createProperty = function (obj, prop, currentValue) { Object.defineProperty(obj, prop, { get: function () { return currentValue; }, set: function (value) { currentValue = value; }, enumerable: true, configurable: true }); } // Adding property and using closure space to save private value for (var index = 0; index < sampleSize; index++) { var entity = {}; var currentValue = "hello world (" + index + ")"; createProperty(entity, "property", currentValue); entities.push(entity); }
Après cela, j'ai exécuté les trois morceaux de code (sur trois navigateurs principaux) et démarré (navigateur) l'analyseur de performances de mémoire intégré (utilisez la barre d'outils F12 dans cet exemple) :
Les résultats de l'exécution sur mon ordinateur sont les suivants :
Concernant l'espace de fermeture et les méthodes conventionnelles, uniquement sur Chrome, les performances de l'espace de fermeture (utilisation de la mémoire) sont légèrement meilleures. Sur IE11 et Firefox, l'utilisation de la mémoire augmente, mais les résultats de comparaison des navigateurs sont e-pour les navigateurs modernes, utilisateurs Vous ne remarquerez probablement pas la différence.
Vous serez peut-être surpris que Microsoft ait fourni un lot de matériel d'apprentissage gratuit sur le thème du Javascript open source, et nous lançons une tâche pour créer davantage de Microsoft Edge à venir série. Consultez mon article :
Développement des bases de WebGL 3D basées sur HTML5 et Babylon.JS
Création d'une application monopage basée sur ASP. NET et AngularJS
Technologie d'image avancée HTML
Ou notre série d'équipe :
HTML/ Conseils d'utilisation pour l'optimisation des performances de JavaScript (cette série comprend 7 parties, de la conception réactive à l'optimisation des performances des jeux occasionnels)
Démarrez rapidement avec les plateformes Web modernes (bases HTML, CSS et JS)
Développez des applications Windows universelles en utilisant HTML et JavaScript pour démarrer rapidement (créez des applications avec votre propre JS)
et quelques outils gratuits : Visuel Studio Community, essais Azure et outils de test multi-navigateurs pour Mac, Linux ou Windows.
Comme vous pouvez le constater, les attributs (mécanismes) de l'espace de fermeture sont un excellent moyen de créer des données véritablement privées. Vous devrez peut-être faire face à une petite augmentation de la consommation de mémoire (problème), mais à mon avis, c'est très raisonnable (ce prix peut être échangé contre une augmentation des performances plus élevée par rapport à la méthode conventionnelle).
En passant, si vous souhaitez l'essayer vous-même, le code peut être téléchargé ici. Recommandez un bon article, « comment faire » sur Azure Mobile Services ici.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!