JavaScript Så här lägger du in privata medlemmar i ett objekt

Jag har nyligen utvecklat Angular Cloud Data Connector, som gör det möjligt för Angular-utvecklare att använda molndata, särskilt Azure Mobile Services, med hjälp av webbstandarder som indexerad DB. Jag försökte skapa ett sätt för JavaScript-utvecklare att integrera privata medlemmar i ett objekt. 

Min teknik för detta specifika fall är att använda det jag kallar "stängningsutrymme". I denna handledning vill jag dela med dig hur man använder det här för egna projekt och hur det påverkar prestanda och minne för de stora webbläsarna.

Men innan du dyker in i det, låt mig dela varför du kanske behöver privata medlemmar, samt ett alternativt sätt att "simulera" privata medlemmar.

Känn dig fri att pinga mig på Twitter om du vill diskutera den här artikeln: @deltakosh.

1. Varför använda privata medlemmar

När du skapar ett objekt med hjälp av JavaScript kan du definiera värdemedlemmar. Om du vill kontrollera läs / skrivåtkomst på dem behöver du accessors som kan definieras så här:

var enhet = ; entity._property = "hej värld"; Object.defineProperty (enhet, "egenskap", get: function () return this._property;, set: funktion (värde) this._property = value;, uppräkningsbar: sant, konfigurerbar: true);

Genom att göra detta har du full kontroll över läs- och skrivoperationer. Problemet är att _fast egendom medlemmen är fortfarande tillgänglig och kan ändras direkt.

Det är just därför du behöver ett mer robust sätt att definiera privata medlemmar som endast kan nås av objektets funktioner.

2. Använda stängningsutrymme

Lösningen är att använda stängningsutrymme. Det här minnesutrymmet är byggt för dig av webbläsaren varje gång en inre funktion har tillgång till variabler från ramen för en yttre funktion. Detta kan vara knepigt ibland, men för vårt ämne är det här en perfekt lösning.

Så låt oss ändra den tidigare koden för att använda den här funktionen:

var skapaProperty = funktion (obj, prop, currentValue) Object.defineProperty (obj, prop, get: funktion () return currentValue;, set: funktion (värde) currentValue = value;, uppräkningsbar: sant, konfigurerbar : Sann );  var enhet = ; var myVar = "hej värld"; createProperty (enhet, "egenskap", myVar);

I det här exemplet är createProperty funktionen har a nuvarande värde variabel som får och sätter funktioner kan se. Denna variabel kommer att sparas i stängningsutrymmet för get och set-funktioner. Endast dessa två funktioner kan nu se och uppdatera nuvarande värde variabel! Uppdrag slutfört!

Det enda som vi har här är att källvärdet (myVar) är fortfarande tillgänglig. Så här kommer en annan version för ännu mer robust skydd:

var createProperty = funktion (obj, prop) var currentValue = obj [prop]; Object.defineProperty (obj, prop, get: funktion () return currentValue;, set: funktion (värde) currentValue = value;, talbar: true, configable: true);  var enhet = egendom: "hej värld"; createProperty (enhet, "egenskap");

Med hjälp av denna metod förstörs även källvärdet. Så uppdraget är fullt uppnått!

3. Prestanda överväganden

Låt oss nu titta på prestanda.

Självklart är stängningsutrymmen eller till och med egenskaper långsammare och dyrare än bara en vanlig variabel. Därför fokuserar denna artikel mer på skillnaden mellan det vanliga sättet och stängningsutrymmet tekniken.

För att bekräfta stängningsutrymmet är inte för dyrt jämfört med det vanliga sättet skrev jag det här lilla riktmärket:

       
Datoranvändning…

Jag skapar 1 miljon objekt, alla med en fastighetsmedlem. Då gör jag tre tester:

  • Gör 1 miljon slumpmässig åtkomst till fastigheten.
  • Gör 1 million slumpmässiga åtkomst till "stängningsutrymme" -versionen.
  • Gör 1 million slumpmässiga åtkomst till den vanliga få / set-versionen.

Här är en tabell och ett diagram över resultaten:

Vi kan se att stängningsutrymmesversionen alltid är snabbare än den vanliga versionen och beroende på webbläsaren, det kan vara en riktigt imponerande optimering.

Chrome-prestanda är mindre än vad jag förväntade mig. Det kan hända att jag är säker på att jag kontaktade Googles team för att ta reda på vad som händer här. Också om du vill testa hur detta fungerar i Microsoft Edge-Microsofts nya webbläsare som skickas som standard med Windows 10, kan du ladda ner det här.

Men om vi tittar noga kan vi konstatera att det går att använda stängningsutrymme eller till och med en fastighet kan vara tio gånger långsammare än direkt tillgång till en medlem. Var så varnas och använd det klokt.

4. Minnesfotavtryck

Vi måste också kontrollera att denna teknik inte förbrukar för mycket minne. För att benchmark minne skrev jag dessa tre små bitar av kod:

Referens kod

var sampleSize = 1000000; var enheter = []; // Skapa enheter för (var index = 0; index < sampleSize; index++)  entities.push( property: "hello world (" + index + ")" ); 

Regelbundet sätt

var sampleSize = 1000000; var enheter = []; // Lägga till egendom och använd lokalmedlem för att spara privatvärde för (varindex = 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); 

Avsluta rymdversionen

var sampleSize = 1000000; var enheter = []; var skapaProperty = funktion (obj, prop, currentValue) Object.defineProperty (obj, prop, get: funktion () return currentValue;, set: funktion (värde) currentValue = value;, uppräkningsbar: sant, konfigurerbar : Sann );  // Lägga till egendom och använda stängningsutrymme för att spara privatvärde för (varindex = 0; index < sampleSize; index++)  var entity = ; var currentValue = "hello world (" + index + ")"; createProperty(entity, "property", currentValue); entities.push(entity); 

Sedan sprang jag alla dessa tre koder och lanserade den inbyggda minnesprofilen (exempel här med hjälp av F12-verktyg):

Här är resultaten jag fick på min dator:

Mellan stängningsutrymme och vanligt sätt har endast Chrome något bättre resultat för stängningsutrymmet. IE11 och Firefox använder lite mer minne, men webbläsarna är relativt jämförbara. Användarna kommer antagligen inte märka någon skillnad över de moderna webbläsarna.

Mer hands-on med JavaScript

Det kan kanske överraska dig lite, men Microsoft har en massa gratis lärande på många JavaScript-ämnen med öppen källkod, och vi har ett uppdrag att skapa mycket mer med Microsoft Edge. Kolla in min egen:

  • Introduktion till WebGL 3D med HTML5 och Babylon.JS
  • Skapa ett enkelsidigt program med ASP.NET och AngularJS
  • Cutting Edge Graphics i HTML

Eller vårt lags inlärningsserie:

  • Praktiska prestationstips för att göra din HTML / JavaScript snabbare (en sju delarserie från lyhörd design till vardagliga spel till prestationsoptimering)
  • Den moderna webbplatformen Jump Start (grunden för HTML, CSS och JS)
  • Utveckla Universal Windows Apps med HTML och JavaScript Jump Start (använd det JS du redan har skapat för att skapa en app)

Och några gratis verktyg: Visual Studio Community, Azure Trial och testverktyg för webbläsare för Mac, Linux eller Windows.

Slutsats

Som du kan se kan stängningsutrymmeegenskaper vara en Bra sätt att skapa riktigt privata data. Det kan hända att du måste hantera en liten ökning av minneskonsumtionen, men ur min synvinkel är det ganska rimligt (och till det priset kan du få en bra prestandaförbättring jämfört med det vanliga sättet).

Och förresten om du vill prova det själv, vänligen hitta all koden som används här. Det finns en bra "hur-till" på Azure Mobile Services här.

Den här artikeln är en del av web dev-tekniken från Microsoft. Vi är glada att dela Microsoft Edge och den nya EdgeHTML-återgivningsmotor med dig. Få gratis virtuella maskiner eller testa fjärran på din Mac, iOS, Android eller Windows-enheten @ http://dev.modern.ie/.

Lär dig JavaScript: Den fullständiga guiden

Vi har byggt en komplett guide för att hjälpa dig att lära dig JavaScript, oavsett om du precis börjat som webbutvecklare eller vill utforska mer avancerade ämnen.