JavaScript privé-leden insluiten in een object

Ik heb onlangs Angular Cloud Data Connector ontwikkeld, waarmee Angular-ontwikkelaars cloudgegevens, met name Azure Mobile Services, kunnen gebruiken met behulp van webstandaarden zoals geïndexeerde DB. Ik probeerde een manier te creëren voor JavaScript-ontwikkelaars om privé-leden in te bedden in een object. 

Mijn techniek voor dit specifieke geval is om te gebruiken wat ik 'sluitruimte' noem. In deze zelfstudie wil ik met u delen hoe u dit voor uw eigen projecten kunt gebruiken en hoe dit de prestaties en het geheugen voor de belangrijkste browsers beïnvloedt..

Maar laat me, voordat je erin duikt, vertellen waarom je misschien privé-leden nodig hebt, en ook een alternatieve manier om privéleden te "simuleren"..

Voel je vrij om me te pingen op Twitter als je dit artikel wilt bespreken: @deltakosh.

1. Waarom privé-leden gebruiken

Wanneer u een object maakt met JavaScript, kunt u waardeleden definiëren. Als u lees- / schrijftoegang op hen wilt beheren, hebt u accessors nodig die als volgt kunnen worden gedefinieerd:

var entity = ; entity._property = "hallo wereld"; Object.defineProperty (entity, "property", get: function () return this._property;, set: function (value) this._property = value;, op te tellen: true, configurable: true);

Door dit te doen, hebt u de volledige controle over lees- en schrijfbewerkingen. Het probleem is dat de _eigendom lid is nog steeds toegankelijk en kan direct worden gewijzigd.

Dit is precies waarom je een meer robuuste manier nodig hebt om privéleden te definiëren die alleen toegankelijk zijn via objectfuncties.

2. Gebruik van de sluitruimte

De oplossing is om sluitruimte te gebruiken. Deze geheugenruimte wordt door de browser voor u gemaakt telkens een innerlijke functie toegang heeft tot variabelen uit de reikwijdte van een externe functie. Dit kan soms lastig zijn, maar voor ons onderwerp is dit een perfecte oplossing.

Dus laten we de vorige code wijzigen om deze functie te gebruiken:

var createProperty = function (obj, prop, currentValue) Object.defineProperty (obj, prop, get: function () return currentValue;, set: function (value) currentValue = value;, opsom: true, configureerbaar : true);  var entity = ; var myVar = "hallo wereld"; createProperty (entity, "property", myVar);

In dit voorbeeld is de CreateProperty functie heeft een huidige waarde variabele die de get en set-functies kunnen zien. Deze variabele wordt opgeslagen in de sluitingsruimte van get en set-functies. Alleen deze twee functies kunnen nu het huidige waarde variabele! Missie volbracht!

Het enige voorbehoud dat we hier hebben, is dat de bronwaarde (myVar) is nog steeds toegankelijk. Dus hier komt nog een versie voor nog meer robuuste bescherming:

var createProperty = function (obj, prop) var currentValue = obj [prop]; Object.defineProperty (obj, prop, get: function () return currentValue;, set: function (value) currentValue = value;, opsommen: true, configurable: true);  var entity = property: "hello world"; createProperty (entity, "property");

Met behulp van deze methode wordt zelfs de bronwaarde vernietigd. Dus missie volledig volbracht!

3. Prestatieoverwegingen

Laten we nu eens kijken naar de prestaties.

Vanzelfsprekend zijn afsluitruimten of zelfs eigenschappen langzamer en duurder dan alleen een gewone variabele. Daarom is dit artikel meer gericht op het verschil tussen de reguliere manier en de sluitruimte-techniek.

Om te bevestigen dat de benadering van de sluitingsruimte niet te duur is in vergelijking met de standaardmanier, heb ik deze kleine benchmark geschreven:

       
Computing ...

Ik maak 1 miljoen objecten, allemaal met een propertylid. Dan doe ik drie tests:

  • Voer 1 miljoen willekeurige toegangen tot het onroerend goed.
  • Voer 1 miljoen willekeurige toegangen tot de "sluitruimte" -versie.
  • Voer 1 miljoen willekeurige toegangen tot de reguliere get / set-versie.

Hier zijn een tabel en een grafiek van de resultaten:

We kunnen zien dat de afsluitruimteversie altijd sneller is dan de reguliere versie en afhankelijk van de browser, het kan een heel indrukwekkende optimalisatie zijn.

De prestaties van Chrome zijn minder dan ik had verwacht. Er is misschien een foutje om zeker te zijn, ik heb contact opgenomen met het Google-team om erachter te komen wat hier gebeurt. Ook als u wilt testen hoe dit presteert in de nieuwe browser van Microsoft Edge-Microsoft die standaard met Windows 10 wordt verzonden, kunt u dit hier downloaden.

Als we echter goed kijken, zien we dat het gebruik van sluitruimte of zelfs een eigenschap tien keer langzamer kan zijn dan directe toegang tot een lid. Dus wees gewaarschuwd en gebruik het verstandig.

4. Geheugenvoetafdruk

We moeten ook controleren dat deze techniek niet te veel geheugen verbruikt. Om het geheugen te benchmarken heb ik deze drie kleine stukjes code geschreven:

Referentie code

var sampleSize = 1000000; var-entiteiten = []; // Entiteiten maken voor (var index = 0; index < sampleSize; index++)  entities.push( property: "hello world (" + index + ")" ); 

Normale manier

var sampleSize = 1000000; var-entiteiten = []; // Eigenschap toevoegen en lokaal lid gebruiken om privéwaarde op te slaan voor (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); 

Closure Space-versie

var sampleSize = 1000000; var-entiteiten = []; var createProperty = function (obj, prop, currentValue) Object.defineProperty (obj, prop, get: function () return currentValue;, set: function (value) currentValue = value;, opsom: true, configureerbaar : true);  // Eigenschap toevoegen en afsluitruimte gebruiken om persoonlijke waarde op te slaan voor (var index = 0; index < sampleSize; index++)  var entity = ; var currentValue = "hello world (" + index + ")"; createProperty(entity, "property", currentValue); entities.push(entity); 

Vervolgens heb ik al deze drie codes uitgevoerd en de ingesloten geheugenprofiler gelanceerd (bijvoorbeeld hier met behulp van F12-hulpmiddelen):

Dit zijn de resultaten die ik op mijn computer heb gekregen:

Tussen sluitingsruimte en normale manier heeft alleen Chrome iets betere resultaten voor de versie met sluitingsruimte. IE11 en Firefox gebruiken een beetje meer geheugen, maar de browsers zijn relatief vergelijkbaar - gebruikers zullen waarschijnlijk geen verschil merken in de moderne browsers.

Meer hands-on met JavaScript

Het zal je misschien een beetje verbazen, maar Microsoft heeft een heleboel gratis leren over veel open source JavaScript-onderwerpen, en we zijn op een missie om nog veel meer te maken met Microsoft Edge coming. Bekijk mijn eigen:

  • Introductie tot WebGL 3D met HTML5 en Babylon.JS
  • Een enkele pagina-applicatie bouwen met ASP.NET en AngularJS
  • Cutting Edge Graphics in HTML

Of de leerserie van ons team:

  • Praktische prestatie-tips om uw HTML / JavaScript sneller te maken (een zevendelige serie van responsief ontwerp tot informele games tot prestatie-optimalisatie)
  • Het startschot voor het moderne webplatform (de fundamenten van HTML, CSS en JS)
  • Universele Windows-apps ontwikkelen met HTML en JavaScript Jump Start (gebruik de JS die u al hebt gemaakt om een ​​app te bouwen)

En enkele gratis tools: Visual Studio Community, Azure Trial en cross-browser testtools voor Mac, Linux of Windows.

Conclusie

Zoals je ziet, kunnen de eigenschappen van de sluitruimte een zijn geweldige manier om echt privégegevens te maken. Je hebt misschien te maken met een kleine toename in geheugengebruik, maar vanuit mijn oogpunt is dit redelijk redelijk (en voor die prijs kun je een geweldige prestatieverbetering krijgen ten opzichte van het gebruik van de normale manier).

En trouwens, als u het zelf wilt proberen, vindt u hier alle code die hier wordt gebruikt. Er is een goede "how-to" op Azure Mobile Services hier.

Dit artikel maakt deel uit van de web dev tech-serie van Microsoft. We zijn verheugd om te delen Microsoft Edge en het nieuwe EdgeHTML-renderingengine met jou. Download gratis virtuele machines of test op afstand op uw Mac, iOS, Android of Windows-apparaat @ http://dev.modern.ie/.

Leer JavaScript: de complete gids

We hebben een complete handleiding samengesteld om u te helpen JavaScript te leren, of u net bent begonnen als een webontwikkelaar of dat u meer geavanceerde onderwerpen wilt verkennen.