Variabelen, arrays, lussen en null begrijpen de post-itnotitie-analogie

Wat doet var eigenlijk doen, en waarom niet instellen myObject = null eigenlijk het object verwijderen? Deze vragen sluiten aan op een fundamenteel concept in de codering, relevant of uw taal naar keuze AS3, JavaScript of C # is, en kan worden begrepen met behulp van een paar algemene items uit de kast voor briefpapier..


Wat is een variabele?

Laten we beginnen met de basis. Stel dat je de leeftijd van je vriend Bill wilt opslaan:

 var ageOfBill: Number = 24;

(Ik ga AS3 gebruiken voor deze voorbeelden, maar de basisconcepten zijn hetzelfde in JavaScript en C #.

In JavaScript is de syntaxis bijna hetzelfde, maar we specificeren niet dat leeftijd een getal is:

 var ageOfBill = 24;

In C # gebruiken we geen var zoekwoord, maar we specificeren het type van de variabele:

 korte ageOfBill = 24;

Niet anders genoeg om verwarrend te zijn, hoop ik.)

Wat is hier aan de hand? Zie het als volgt:

  • var (of kort, in C #) betekent "een nieuwe Post-it-notitie krijgen".
  • ageOfBill betekent: "schrijven ageOfBill over de top, in pen ".
  • = 24 betekent: "schrijven 24 op de notitie, in potlood ".

Wat als we later beseffen dat Bill eigenlijk jonger is dan we dachten?

 var ageOfBill = 24; // ... later ... ageOfBill = 20;

Dit betekent alleen dat we onze vinden ageOfBill notitie, wissen 24, en schrijf 20 in plaats daarvan.

Wij kon schrijven var nog een keer:

 var ageOfBill: Number = 24; // ... later ... var ageOfBill: Number = 20;

... maar dit is geen goede code, want var zegt: "ontvang een nieuwe Post-it-notitie". Als je dit doet, zal de compiler meestal achterhalen wat je bedoelt, dat wil zeggen dat je wilt wijzigen wat er op het bestaande staat geschreven ageOfBill Post-it note in plaats van een nieuwe te krijgen, maar het zal waarschijnlijk klagen.

 Waarschuwing: # 3596: dubbele variabele definitie.

Het hangt af van de taal en van uw codeeromgeving.

Dus kunnen we de compiler vragen om een ​​nieuw Post-it-briefje te schrijven en er een label op te schrijven in de pen, zonder er iets in potlood in op te schrijven? Misschien kunnen we dit doen voor Bill's vriend Marty, van wie we de leeftijd niet weten:

 var ageOfMarty: Number;

Eigenlijk (tenminste in AS3) krijgt dit een nieuwe Post-it-noot, schrijf ageOfMarty aan de bovenkant, in pen ... en schrijf dan een standaard beginwaarde van 0 daar in potlood:

Met andere woorden, we kunnen geen Post-it-notitie krijgen zonder dat dit enige waarde heeft.

Oké, wat als we de leeftijd van Bill's beste vriend Ted willen opslaan, waarvan we weten dat hij dezelfde leeftijd heeft?

 var ageOfTed: Number = ageOfBill;

Wat hier gebeurt, is dat de computer naar de ageOfBill Post-it, kopieert het daarop geschreven getal in potlood naar een nieuwe Post-it, waarop het schrijft ageOfTed over de top in pen.

Dit is echter maar een kopie; als we dan de waarde van veranderen ageOfBill het heeft geen invloed op ageOfTed:

 ageOfBill = 21;

Zo! Dat is allemaal vrij eenvoudig en misschien zelfs intuïtief. Laten we het nu hebben over het eerste algemene pijnpunt: arrays.


Wat is een array??

Beschouw een array als een ringband.

(Ik wou een rolodex zeggen ...

... maar ik besefte dat ik er nog nooit een in het echt had gezien.)

Elk vel in de map is als een van die Post-it-notities, behalve zonder het pen-geschreven label aan de bovenkant. In plaats daarvan verwijzen we naar elk blad door de naam van het bindmiddel en het paginanummer van het blad.

Laten we aannemen dat we een hele reeks van al onze vrienden hebben, in willekeurige volgorde. Wie staat op de eerste pagina (pagina # 0)?

 trace (vrienden [0]);

(spoor() schrijft gewoon de regel naar de debug-uitvoer; in JavaScript, zou je kunnen gebruiken console.log () en in C # zou je kunnen gebruiken Console.WriteLine () voor hetzelfde doel.)

Het is Bill!

Wat doet de volgende regel nu??

 var firstFriend: String = friends [0];

Het krijgt een nieuwe Post-it-noot (vanwege de var trefwoord), schrijft firstFriend aan de bovenkant in een pen, kopieert vervolgens alles wat op de eerste pagina van de binder is geschreven naar die notitie in potlood.

(Onthouden, Draad betekent gewoon een stukje tekst.)

We kunnen overschrijven wat er op een willekeurige pagina van de map is geschreven, net als bij de Post-it-notities:

 vrienden [0] = "Kyle";

... en natuurlijk heeft dit geen effect op de firstFriend Post-it.

Het bindmiddel is een toepasselijke analogie, omdat je - net als bij een array - pagina's eruit haalt, nieuwe toevoegt en opnieuw induikt. Maar vergeet niet dat afzonderlijke pagina's net zo werken als de Post-it-notities, behalve dat ze geen eigen penlabels hebben, maar alleen paginanummers.

Nog steeds vrij eenvoudig, hoop ik. Dus hier is een interessante vraag: wat gebeurt er als je het volgende doet?

 var listOfNames: Array = vrienden;

Uh ...


Dat kun je niet schrijven op een post-it

Ik heb hier een beetje vals gespeeld, omdat ik een stel over arrays heb gesproken zonder ooit te hebben uitgelegd hoe we er een maken. Laten we dat nu aanpakken.

Stel dat je typt:

 var vrienden: Array = ["Bill", "Marty", "Ted"];

… Wat gebeurt er?

Nou, zoals gewoonlijk, var vrienden betekent dat we een nieuwe Post-it-notitie krijgen en schrijven vrienden over de top, in pen:

Maar wat schrijven we er in potlood op?

Het is een strikvraag: we schrijven niet iets.

Zien, reeks betekent: "een nieuwe ringband kopen". En ["Bill", "Marty", "Ted"] betekent "plaats drie pagina's in de map, met deze namen erop":


Je kunt de pagina's "Marty" en "Ted" niet zien, maar ze zijn er helemaal.

En dan? Het is makkelijk! We houden het vrienden Post-it note op de omslag van de map:

Nu, wanneer we schrijven:

 trace (vrienden [0]);

... we weten dat we het Post-it-label moeten vinden vrienden, kijk dan naar wat er geschreven staat op de eerste pagina (pagina # 0) van het bindmiddel waar het aan vastzit.

Er zijn eigenlijk maar heel weinig soorten variabelen waar een waarde in potlood op een Post-it-notitie wordt geschreven. In AS3 zijn de enige dergelijke typen ("primitieven" genoemd):

  • Aantal
  • Draad
  • int
  • uint
  • Boolean

Voor al het andere - Voorwerp, Filmclip, XML, en zo verder - we plakken de Post-it-notitie op het item zelf.

(De details zijn een beetje anders in JavaScript en C #, maar over het algemeen geldt hetzelfde idee.)

Dus laten we teruggaan naar onze eerdere vraag. Wanneer typen we:

 var listOfNames: Array = vrienden;

… wat gebeurt er?

Nogmaals, dat weten we var listOfNames betekent "een nieuwe Post-it-notitie krijgen en schrijven listOfNames aan de bovenkant in de pen. "En nu weten we dat reeks betekent dat we de Post-it-notitie aan iets (een binder) plakken, in plaats van iets op de Post-it in potlood te schrijven.

Eerder, toen we iets soortgelijks hebben gedaan, hebben we de inhoud van de ene Post-it-notitie naar de andere gekopieerd. Dus hier moeten we een nieuwe nieuwe map krijgen en alle pagina's van de vrienden bindmiddel erin?

Eigenlijk niet! Het enige wat we doen is dit nieuw houden listOfNames Post-it notitie op dezelfde map als de vrienden Post-it notitie.

Nu, vrienden en listOfNames elk verwijst naar de exact dezelfde reeks. Dus als we schrijven:

 listOfNames [0] = "Emmett";

… dan vrienden [0] zullen ook worden Emmett, omdat listOfNames [0] en vrienden [0] raadpleeg exact dezelfde pagina in exact dezelfde map! En omdat die pagina alleen een tekenreeks bevat (wat een 'primitief' type is, onthoud), hebben we net alles gewist wat eerder op die pagina is geschreven en geschreven Emmett daar in plaats daarvan.


Dus wat doet het nul Gemiddelde?

Zo gezien, nul is vrij gemakkelijk te begrijpen. Deze verklaring:

 vrienden = null;

... betekent gewoon: "verwijder de vrienden Post-it notitie van waar het momenteel aan vastzit ".

De vrienden Post-it nog steeds bestaat, het zit gewoon nergens aan vast. Dus als u typt:

 trace (vrienden [0]);

of

 vrienden [0] = "Henry";

... dan krijg je een foutmelding, omdat je probeert te verwijzen naar de eerste pagina van de map waarin de vrienden Post-it zit vast aan - maar het zit nergens aan vast!

Dus, voor de duidelijkheid, het instellen vrienden = null heeft helemaal geen invloed op het bindmiddel. Je hebt er nog steeds prima toegang toe via listOfNames. En je kunt zelfs typen:

 vrienden = listOfNames;

... om terug te gaan naar de oude situatie:


Garbage Collection

Zoals ik al zei, instelling vrienden = null heeft geen rechtstreeks effect op het bindmiddel, maar het kan een indirect effect.

Kijk, als er helemaal geen Post-it-biljetten aan de map zitten, kan niemand de map ooit nog gebruiken. Het zal gewoon rondslingeren, totaal ontoegankelijk. Maar al deze binders (en andere objecten) rondslingeren, volledig in de steek gelaten, is een echte verspilling van ruimte - ze maken het computergeheugen voller.

Dat is waar de vuilnisman komt binnen. Dit is een tool die regelmatig op zoek gaat naar 'verloren' objecten en ze in de prullenbak gooit - en als ze weg zijn, zijn ze voor altijd weg; als een array vuilnis verzameld is, zijn alle pagina's dat ook.

Voor de meeste praktische doeleinden heeft dit helemaal geen invloed op u; objecten krijgen alleen garbage verzameld als ze verloren zijn en niet kunnen worden gevonden door je code. Als je veel van deze rondslingert, dan kun je af en toe een lichte vertraging opmerken, wanneer de vuilnisman zijn werk doet (het kost wat tijd om actief de vuilnis te verzamelen). Het voordeel is dat dit meer ruimte (geheugen) voor uw app opruimt.

(Als u meer wilt weten over dit onderwerp, lees dan Daniel Sidhion's berichten over garbage collection en object pooling.)


Arrays of Objects

Oké, er is nog een groot concept om te begrijpen - en het is de meest complexe.

Overweeg dit fragment:

 var firstFriendDetails: Array = ["Bill", 20]; var secondFriendDetails: Array = ["Marty", 16]; var thirdFriendDetails: Array = ["Ted", 20]; var allFriends: Array = [firstFriendDetails, secondFriendDetails, thirdFriendDetails];

Hoe gaat het in godsnaam dat werk?

Laten we beginnen met wat we weten. De eerste drie regels zijn eenvoudig; voor elke we hebben we:

  • Koop een nieuw bindmiddel.
  • Plaats een pagina met de naam van de vriend erop geschreven in potlood.
  • Voor een andere pagina waarop de leeftijd van de vriend staat geschreven in potlood.
  • Ontvang een nieuwe Post-it en schrijf het juiste label bovenaan in de pen.
  • Plak de Post-it op de binder.

Wat betreft deze regel:

 var allFriends: Array = [firstFriendDetails, secondFriendDetails, thirdFriendDetails];

... we hebben wat touwtjes en wat tape nodig.

We kunnen aan die ene regel denken als gelijkwaardig aan dit fragment:

 var allFriends: Array = []; allFriends [0] = firstFriendDetails; allFriends [1] = secondFriendDetails; allFriends [2] = thirdFriendDetails;

De eerste regel is eenvoudig: krijg een nieuwe binder en een nieuwe Post-it-notitie, schrijf allFriends op de Post-it-notitie en plak deze op de binder.

Wat betreft de tweede regel:

 allFriends [0] = firstFriendDetails;

Vergeet niet dat ik heb gezegd dat elke pagina in een map als een Post-it-notitie is, behalve zonder dat iets in een pen is geschreven. Als de eerste pagina een post-it was, dan zouden we hem gewoon aan de voorkant van de firstFriendDetails map, rechts?

... maar het kan niet beide op de voorkant van die map staan en in het andere bindmiddel. In plaats daarvan gebruiken we tekenreeks:

Hetzelfde voor de andere twee:

Dus wanneer we willen weten wat allFriends [2] verwijst naar, we openen gewoon de allFriends bind naar die pagina en volg de string - wat natuurlijk leidt naar de thirdFriendDetails binder.

Evenzo, voor allFriends [1] [0], we zoeken eerst naar welk bindmiddel allFriends [1] verwijst naar, en dan kijken we naar de eerste pagina van dat bindmiddel ... dus allFriends [1] [0] is Marty!


Loops

Zet nu al die informatie bij elkaar en houd er rekening mee bij het lezen van dit fragment:

 var vrienden: Array = ["Bill", "Marty", "Ted", "Emmett", "Henry"]; var currentIndex: int = 0; var currentFriend: String; while (currentIndex < 5)  currentFriend = friends[currentIndex]; trace(currentFriend);  var lastFriend:String = currentFriend; trace(lastFriend);

Wat als we de waarde van wijzigen currentFriend in de lus?

 var vrienden: Array = ["Bill", "Marty", "Ted", "Emmett", "Henry"]; var currentIndex: int = 0; var currentFriend: String; while (currentIndex < 5)  currentFriend = friends[currentIndex]; currentFriend = "Herbert"; trace(currentFriend);  trace(friends[0]);

Wat als de array niet-primitieve objecten bevat (MovieClips, afbeeldingen, matrices, 3D-objecten, wat dan ook)?

 var friends: Array = [firstFriend, secondFriend, thirdFriend, fourthFriend, fifthFriend]; var currentIndex: int = 0; var currentFriend: MovieClip; // of ": Afbeelding" of ": Object" of ": Array" of iets dergelijks (currentIndex < 5)  currentFriend = friends[currentIndex]; currentFriend = sixthFriend;  //What is the value of friends[0] now?

Ten slotte, wat als de array andere arrays bevat die zelf primitieven bevatten?

 var firstFriendDetails: Array = ["Bill", 20]; var secondFriendDetails: Array = ["Marty", 16]; var thirdFriendDetails: Array = ["Ted", 20]; var fourthFriendDetails: Array = ["Emmett", 50]; var fifthFriendDetails: Array = ["Henry", 36]; var friends: Array = [firstFriendDetails, secondFriendDetails, thirdFriendDetails, fourthFriendDetails, fifthFriendDetails]; var currentIndex: int = 0; var currentFriend: Array; while (currentIndex < 5)  currentFriend = friends[currentIndex]; currentFriend[0] = "John"; currentFriend = ["Herbert", 29]; 

Wat denk je dat de waarde van vrienden [3] [0] zal daarna zijn?


Andere stukjes en beetjes

Hier zijn een paar andere belangrijke opmerkingen die u moet weten:

Voorwerpen

In AS3 en JavaScript zijn objecten vergelijkbaar met arrays, behalve dat elke pagina wordt aangeduid door een label in plaats van het paginanummer. Je kunt dus typen:

 var detailsOfBill: Object = ; // "" betekent "maak een object" detailsOfBill.title = "Esquire"; detailsOfBill.bandName = "Wyld Stallyns"; detailsOfBill.allNames = ["Bill", "S.", "Preston"];

… en dit is soort van zoals het krijgen van een nieuw bindmiddel, het plakken van een detailsOfBill Post-it aan de voorkant en vullen met drie pagina's. De eerste pagina heeft het label titel geschreven over de top in pen en het woord schildknaap erop geschreven in potlood; de tweede pagina heeft het label band naam in pen en Wyld Stallyns in potlood. De derde pagina heeft het label allNames maar heeft er niets in potlood opgeschreven; in plaats daarvan bevestigt een reeks deze aan een ander, normaal bindmiddel, waarvan de pagina's niet zijn gelabeld: de eerste pagina zegt Bill, de tweede zegt S., en de derde zegt Preston, alles in potlood.

(Om dingen nog verwarrender te maken, zijn arrays technisch gezien een speciale vorm van Object. En als je denkt dat dat slecht is, kunnen functies ook als een soort Object worden gezien! Maar dat is een onderwerp voor een toekomstig artikel ...)

Meer over Garbage Collection

Ik zei dat objecten vuilnis zijn verzameld als ze geen Post-it-biljetten aan zich hebben, maar dit is een te grote vereenvoudiging. Als een pagina van een binder naar een object wijst via een tekenreeks (dus als myArray [0] = myObject of vergelijkbaar), dan wordt dat object niet als afval verzameld. Hetzelfde geldt voor als een pagina van een binder naar een ander binder (array) wijst, of als de pagina van een objectbinder naar een andere objectbinder wijst ... en zo verder. Het is zelfs van toepassing als de enige manier om toegang tot het object te krijgen, is via een Post-it die vastzit aan een map die één pagina heeft die is verbonden met een ander binder, zoveel lagen diep als je maar wilt.

In principe verzamelt de garbagecollector alleen een item als het niet via een andere variabele kan worden bereikt.

Dit verklaart waarom objecten die zich op het scherm bevinden meestal niet als object kunnen worden verzameld. Als in AS3 een MovieClip of een ander type DisplayObject in de weergavelijst staat, wordt deze automatisch toegevoegd aan wat in feite een verborgen array van weergaveobjecten is (die u kunt openen via getChildAt ()). Vergelijkbare structuren bestaan ​​in JavaScript en C #. Dus als er een afbeelding op het scherm staat en u alle verwijzingen ernaar verwijdert uit variabelen, arrays en objecten, wordt deze nog steeds niet verzameld totdat u deze uit de weergavelijst verwijdert.


Nog vragen?

Ik hoop dat dit helpt om dingen duidelijk te maken. Het is zeker een verwarrend concept als je het voor het eerst tegenkomt: sommige variabelen bevatten eigenlijk een waarde, terwijl anderen alleen een bevatten referentie naar een object. Maak je geen zorgen als je niet 100% zeker weet wat er aan de hand is; het zal veel logischer zijn na een beetje oefenen (en een paar fouten!).

Als u echter specifieke vragen heeft, kunt u hieronder een opmerking plaatsen en ik zal mijn best doen om te antwoorden.

Bedankt voor het lezen!