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..
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.
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 ...
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":
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.
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:
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.)
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:
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
!
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?
Hier zijn een paar andere belangrijke opmerkingen die u moet weten:
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 ...)
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.
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!