JavaScript Come incorporare membri privati ​​in un oggetto

Recentemente ho sviluppato Angular Cloud Data Connector, che consente agli sviluppatori angolari di utilizzare i dati del cloud, in particolare i servizi mobili di Azure, utilizzando standard web come il DB indicizzato. Stavo cercando di creare un modo per gli sviluppatori JavaScript per incorporare membri privati ​​in un oggetto. 

La mia tecnica per questo caso specifico è usare quello che chiamo "spazio di chiusura". In questo tutorial, voglio condividere con te come utilizzare questo per i tuoi progetti e come influenza le prestazioni e la memoria per i principali browser.

Ma prima di immergerci, lascia che ti spieghi perché potresti aver bisogno di membri privati, oltre a un modo alternativo di "simulare" i membri privati.

Sentiti libero di darmi un ping su Twitter se vuoi discutere questo articolo: @deltakosh.

1. Perché utilizzare membri privati

Quando si crea un oggetto utilizzando JavaScript, è possibile definire i membri del valore. Se si desidera controllare l'accesso in lettura / scrittura su di essi, sono necessari accessor che possono essere definiti in questo modo:

var entity = ; entity._property = "Ciao mondo"; Object.defineProperty (entità, "proprietà", get: function () return this._property;, set: function (value) this._property = value;, enumerable: true, configurable: true);

In questo modo, hai il pieno controllo sulle operazioni di lettura e scrittura. Il problema è che il _proprietà membro è ancora accessibile e può essere modificato direttamente.

Questo è esattamente il motivo per cui è necessario un modo più efficace per definire membri privati ​​a cui è possibile accedere solo tramite le funzioni dell'oggetto.

2. Utilizzo dello spazio di chiusura

La soluzione è usare lo spazio di chiusura. Questo spazio di memoria è costruito per te dal browser ogni volta che una funzione interna ha accesso alle variabili dall'ambito di una funzione esterna. Questo può essere difficile a volte, ma per il nostro argomento questa è una soluzione perfetta.

Quindi modifichiamo il codice precedente per utilizzare questa funzione:

var createProperty = function (obj, prop, currentValue) Object.defineProperty (obj, prop, get: function () return currentValue;, set: function (valore) currentValue = value;, enumerable: true, configurable : vero );  var entity = ; var myVar = "Ciao mondo"; createProperty (entità, "proprietà", myVar);

In questo esempio, il createProperty la funzione ha a valore corrente la variabile che può ottenere e impostare le funzioni può vedere. Questa variabile verrà salvata nello spazio di chiusura delle funzioni get e set. Solo queste due funzioni ora possono vedere e aggiornare il valore corrente variabile! Missione compiuta!

L'unica avvertenza che abbiamo qui è che il valore di origine (myVar) è ancora accessibile. Quindi ecco che arriva un'altra versione per una protezione ancora più robusta:

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 (entità, "proprietà");

Usando questo metodo, anche il valore sorgente viene distrutto. Quindi missione pienamente compiuta!

3. Considerazioni sulle prestazioni

Diamo ora un'occhiata alle prestazioni.

Ovviamente, gli spazi di chiusura o anche le proprietà sono più lenti e più costosi di una semplice variabile. Ecco perché questo articolo si concentra maggiormente sulla differenza tra il modo regolare e la tecnica dello spazio di chiusura.

Per confermare l'approccio dello spazio di chiusura non è troppo costoso rispetto al modo standard, ho scritto questo piccolo punto di riferimento:

       
Informatica ...

Creo 1 milione di oggetti, tutti con un membro di proprietà. Quindi faccio tre test:

  • Effettua 1 milione di accessi casuali alla proprietà.
  • Effettua 1 milione di accessi casuali alla versione "spazio di chiusura".
  • Effettua 1 milione di accessi casuali alla normale versione get / set.

Ecco una tabella e una tabella dei risultati:

Possiamo vedere che la versione dello spazio di chiusura è sempre più veloce rispetto alla versione normale e dipende dal browser, può essere un'ottimizzazione davvero impressionante.

Le prestazioni di Chrome sono meno di quanto mi aspettassi. Potrebbe esserci un bug, per sicurezza, ho contattato il team di Google per capire cosa sta succedendo qui. Inoltre, se vuoi testare come funziona in Microsoft Edge, il nuovo browser Microsoft che verrà fornito con Windows 10, puoi scaricarlo qui.

Tuttavia, se osserviamo da vicino, possiamo scoprire che l'utilizzo dello spazio di chiusura o persino di una proprietà può essere dieci volte più lento dell'accesso diretto a un membro. Quindi avvisati e usalo saggiamente.

4. Impronta di memoria

Dobbiamo anche verificare che questa tecnica non consumi troppa memoria. Per confrontare la memoria ho scritto questi tre piccoli pezzi di codice:

Codice di riferimento

var sampleSize = 1000000; var entities = []; // Creazione di entità per (var index = 0; index < sampleSize; index++)  entities.push( property: "hello world (" + index + ")" ); 

Modo normale

var sampleSize = 1000000; var entities = []; // Aggiunta di proprietà e utilizzo di un membro locale per il salvataggio di valori privati ​​per (indice var = 0; indice < 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); 

Versione dello spazio di chiusura

var sampleSize = 1000000; var entities = []; var createProperty = function (obj, prop, currentValue) Object.defineProperty (obj, prop, get: function () return currentValue;, set: function (valore) currentValue = value;, enumerable: true, configurable : vero );  // Aggiunta di proprietà e utilizzo dello spazio di chiusura per il salvataggio di valori privati ​​per (indice var = 0; indice < sampleSize; index++)  var entity = ; var currentValue = "hello world (" + index + ")"; createProperty(entity, "property", currentValue); entities.push(entity); 

Poi ho eseguito tutti questi tre codici e lanciato il profilo di memoria incorporato (esempio qui con gli strumenti F12):

Ecco i risultati che ho ottenuto sul mio computer:

Tra lo spazio di chiusura e il modo normale, solo Chrome ha risultati leggermente migliori per la versione dello spazio di chiusura. IE11 e Firefox usano un po 'più di memoria, ma i browser sono relativamente comparabili - gli utenti probabilmente non noteranno differenze tra i browser moderni.

Più mani con JavaScript

Potrebbe sorprendervi un po ', ma Microsoft ha un sacco di apprendimento gratuito su molti argomenti JavaScript open source, e siamo in missione per creare molto di più con Microsoft Edge in arrivo. Controlla il mio:

  • Introduzione a WebGL 3D con HTML5 e Babylon.JS
  • Creazione di un'applicazione a pagina singola con ASP.NET e AngularJS
  • Grafica all'avanguardia in HTML

Oppure le serie di apprendimento del nostro team:

  • Suggerimenti pratici sulle prestazioni per rendere il tuo HTML / JavaScript più veloce (una serie in sette parti dal design reattivo ai giochi casuali all'ottimizzazione delle prestazioni)
  • La piattaforma Web moderna Jump Start (i fondamenti di HTML, CSS e JS)
  • Sviluppo di app di Windows universali con HTML e JavaScript Jump Start (usa il JS che hai già creato per creare un'app)

E alcuni strumenti gratuiti: Visual Studio Community, Azure Trial e strumenti di test cross-browser per Mac, Linux o Windows.

Conclusione

Come puoi vedere, le proprietà dello spazio di chiusura possono essere a ottimo modo per creare dati davvero privati. Potrebbe essere necessario affrontare un piccolo aumento del consumo di memoria, ma dal mio punto di vista questo è abbastanza ragionevole (e a quel prezzo si può avere un grande miglioramento delle prestazioni rispetto all'uso regolare).

E comunque se vuoi provarlo da solo, ti preghiamo di trovare tutto il codice usato qui. Qui c'è un buon "how-to" su Azure Mobile Services.

Questo articolo fa parte della serie di web dev tech di Microsoft. Siamo entusiasti di condividere Microsoft Edge e il nuovo Motore di rendering EdgeHTML con te. Ottieni macchine virtuali gratuite o test in remoto sul tuo dispositivo Mac, iOS, Android o Windows @ http://dev.modern.ie/.

Scopri JavaScript: la guida completa

Abbiamo creato una guida completa per aiutarti a imparare JavaScript, sia che tu stia appena iniziando come sviluppatore web o che desideri esplorare argomenti più avanzati.