Cosa fa var
in realtà, e perché non impostare myObject = null
effettivamente rimuovere l'oggetto? Queste domande si collegano a un concetto fondamentale nella codifica, pertinente sia che la lingua di scelta sia AS3, JavaScript o C #, e possa essere compresa utilizzando alcuni elementi comuni dall'armadietto della cancelleria.
Iniziamo con le basi. Immagina di voler archiviare l'età del tuo amico Bill:
var ageOfBill: Number = 24;
(Userò AS3 per questi esempi, ma i concetti di base sono gli stessi in JavaScript e C #.
In JavaScript, la sintassi è quasi la stessa, ma non specificiamo che l'età è un numero:
var ageOfBill = 24;
In C # non usiamo il var
parola chiave, ma specifichiamo il tipo di variabile:
short ageOfBill = 24;
Non è abbastanza diverso da essere fonte di confusione, spero.)
Quindi cosa sta succedendo qui? Pensare in questo modo:
var
(o corto
, in C #) significa "prendi un nuovo post-it".ageOfBill
significa, "scrivi ageOfBill
attraverso la parte superiore, nella penna ".= 24
significa, "scrivi 24
sulla nota, a matita ".Che cosa succede se più tardi ci rendiamo conto che Bill è in realtà più giovane di quanto pensassimo?
var ageOfBill = 24; // ... later ... ageOfBill = 20;
Questo significa solo che troviamo il nostro ageOfBill
nota, cancella 24
, e scrivi 20
su di esso invece.
Noi poteva Scrivi var
ancora:
var ageOfBill: Number = 24; // ... later ... var ageOfBill: Number = 20;
... ma questo non è un buon codice, perché var
dice "prendi un nuovo post-it". Se lo fai, il compilatore di solito capirà cosa intendi - cioè che vuoi cambiare ciò che è scritto sull'esistente ageOfBill
Post-it piuttosto che riceverne uno nuovo, ma probabilmente si lamenterà.
Avviso: n. 3596: definizione variabile delle duplicazioni.
Dipende dalla lingua e dal tuo ambiente di programmazione.
Quindi possiamo chiedere al compilatore di ottenere un nuovo post-it e scrivere un'etichetta su di esso a penna, senza scrivere nulla su di esso a matita? Forse potremmo farlo per l'amico di Bill, Marty, di cui non conosciamo l'età:
var ageOfMarty: Number;
In realtà (in AS3, almeno) questo otterrà un nuovo post-it, scrivi ageOfMarty
attraverso la parte superiore, nella penna ... e quindi scrivere un valore iniziale predefinito di 0
lì a matita:
Quindi, in altre parole, non possiamo avere un post-it come questo senza che abbia un valore.
Okay, che dire se vogliamo archiviare l'età del migliore amico di Bill, Ted, che sappiamo avere la stessa età?
var ageOfTed: Number = ageOfBill;
Quello che succede qui è che il computer guarda il ageOfBill
Post-it, quindi copia il numero scritto su di esso a matita su un Post-it nuovo, sul quale scrive ageOfTed
attraverso la parte superiore a penna.
Questa è solo una copia, però; se poi cambiamo il valore di ageOfBill
non influenzerà ageOfTed
:
ageOfBill = 21;
Così! È tutto molto semplice e forse anche intuitivo. Ora parliamo del primo punto comune di dolore: gli array.
Pensa a un array come un raccoglitore ad anelli.
(Stavo per dire un rolodex ...
... ma mi sono reso conto che non ne avevo mai visto uno nella vita reale.)
Ogni foglio all'interno del raccoglitore è come una di quelle note Post-it, tranne che senza l'etichetta scritta a penna nella parte superiore. Invece, ci riferiamo a ciascun foglio con il nome del raccoglitore e il numero di pagina del foglio.
Supponiamo di avere una schiera di tutti i nostri amici, senza un ordine particolare. Chi è nella prima pagina (pagina # 0)?
trace (amici [0]);
(traccia()
scrive solo la riga sull'output di debug; in JavaScript, potresti usare console.log ()
e in C # potresti usare Console.WriteLine ()
per lo stesso scopo.)
È Bill!
Quindi, ora, cosa fa la seguente linea?
var firstFriend: String = friends [0];
Ottiene un nuovo post-it (a causa del var
parola chiave), scrive firstFriend
attraverso la parte superiore a penna, quindi copia ciò che è scritto sulla prima pagina del raccoglitore su quella nota a matita.
(Ricorda, Stringa
significa solo un pezzo di testo.)
Possiamo sovrascrivere ciò che è scritto su qualsiasi pagina del raccoglitore, proprio come con le note Post-it:
amici [0] = "Kyle";
... e ovviamente questo non influenza il firstFriend
Pubblicalo.
Il raccoglitore è un'analogia azzeccata, perché - proprio come con un array - si prendono fuori pagine, ne si aggiungono di nuove e si riorganizzano. Ma ricorda, le singole pagine agiscono proprio come le note Post-it, tranne che non hanno le loro etichette, solo i numeri di pagina.
Ancora piuttosto semplice, spero. Quindi ecco una domanda interessante: cosa succede quando fai quanto segue?
var listOfNames: Array = friends;
Uh ...
Ho imbrogliato un po 'qui, perché ho parlato un sacco di matrici senza mai spiegare come ne creiamo una in primo luogo. Quindi affrontiamolo adesso.
Supponiamo di digitare:
var friends: Array = ["Bill", "Marty", "Ted"];
… Che succede?
Bene, come al solito, vari amici
significa che riceviamo un nuovo post-it e scriviamo amici
attraverso la parte superiore, nella penna:
Ma cosa scriviamo a matita?
È una domanda trabocchetto: non scriviamo nulla.
Vedere, schieramento
significa "prendi un nuovo raccoglitore ad anelli". E ["Bill", "Marty", "Ted"]
significa "metti tre pagine nel raccoglitore, con sopra questi nomi":
E poi? È semplice! Attacchiamo il amici
Post-it alla copertina del raccoglitore:
Ora, quando scriviamo:
trace (amici [0]);
... sappiamo che dobbiamo trovare l'etichetta Post-it amici
, quindi guarda ciò che è scritto sulla prima pagina (pagina # 0) del raccoglitore a cui è attaccato.
Ci sono in realtà pochissimi tipi di variabili in cui un valore viene scritto su una nota Post-it a matita. In AS3, i soli tipi di questo tipo (chiamati "primitivi") sono:
Numero
Stringa
int
uint
booleano
Per tutto il resto - Oggetto
, Un filmato
, XML
, e così via - incolliamo la nota Post-it sull'oggetto stesso.
(I dettagli sono leggermente diversi in JavaScript e C #, ma nel complesso vale la stessa idea).
Quindi torniamo alla nostra precedente domanda. Quando scriviamo:
var listOfNames: Array = friends;
… che succede?
Ancora una volta, lo sappiamo var listOfNames
significa "prendi un nuovo post-it e scrivi listOfNames
in cima alla penna ". E ora lo sappiamo schieramento
significa che incolleremo la Post-it su qualcosa (un raccoglitore), piuttosto che scrivere qualcosa sul Post-it a matita.
In precedenza, quando abbiamo fatto qualcosa di simile, abbiamo copiato il contenuto di una nota Post-it su un'altra. Quindi, qui dovremmo ottenere un nuovo raccoglitore fresco e copiare tutte le pagine dal amici
legatura in esso?
In realtà no! Tutto ciò che facciamo è attaccare questo nuovo listOfNames
Post-it sullo stesso raccoglitore di amici
Post-it.
Adesso, amici
e listOfNames
ciascuno si riferisce al esattamente lo stesso array. Quindi se scriviamo:
listOfNames [0] = "Emmett";
… poi amici [0]
volontà anche essere Emmett
, perché listOfNames [0]
e amici [0]
fare riferimento alla stessa pagina nello stesso identico raccoglitore! E poiché quella pagina contiene solo una stringa (che è un tipo "primitivo", ricorda), allora abbiamo appena cancellato ciò che è stato scritto su quella pagina in precedenza e scritto Emmett
lì invece.
nullo
Significare?Visto così, nullo
è abbastanza facile da capire. Questa dichiarazione:
amici = null;
... significa solo "rimuovere il amici
Post-it da qualsiasi cosa sia attualmente bloccata a ".
Il amici
Post-it ancora esiste, non è bloccato a nulla. Quindi se scrivi:
trace (amici [0]);
o
amici [0] = "Henry";
... allora riceverai un errore, perché stai cercando di fare riferimento alla prima pagina del raccoglitore che il amici
Post-it è bloccato a - ma non è bloccato a nulla!
Quindi, per essere chiari, l'impostazione amici = null
non ha alcun effetto sul raccoglitore. Puoi ancora accedervi semplicemente via listOfNames
. E puoi anche digitare:
amici = listOfNames;
... per tornare subito alla vecchia situazione:
Come ho detto, ambientazione amici = null
non influenza direttamente il raccoglitore, ma può avere un indiretto effetto.
Vedi, se non ci sono post-it incollati al raccoglitore, allora non c'è modo per nessuno di accedere di nuovo al raccoglitore. Rimarrà solo, totalmente inaccessibile. Ma avere tutti questi raccoglitori (e altri oggetti) in giro, completamente abbandonati, è una vera perdita di spazio - stanno ingombrando la memoria del computer.
Ecco dove il netturbino entra in gioco. Si tratta di uno strumento che verifica periodicamente la presenza di oggetti "persi" e li getta nella spazzatura - e una volta che se ne sono andati, se ne vanno per sempre; se un array è garbage collection allora anche tutte le sue pagine sono.
Per la maggior parte degli scopi pratici, questo non ha alcun effetto su di te; gli oggetti ottengono la garbage collection solo se vengono persi e non possono essere trovati dal codice. Se ne hai molti in giro, potresti notare un leggero ritardo ogni tanto, quando il garbage collector fa il suo lavoro (ci vuole un po 'di tempo per raccogliere attivamente la spazzatura). Il vantaggio è che questo cancella più spazio (memoria) per la tua app.
(Se vuoi saperne di più su questo argomento, leggi i post di Daniel Sidhion su garbage collection e object pooling.)
Ok, c'è un altro grande concetto da cogliere - ed è ancora più complesso.
Considera questo snippet:
var firstFriendDetails: Array = ["Bill", 20]; var secondFriendDetails: Array = ["Marty", 16]; var thirdFriendDetails: Array = ["Ted", 20]; var allFriends: Array = [firstFriendDetails, secondFriendDetails, thirdFriendDetails];
Come diavolo fa? quello lavoro?
Iniziamo con ciò che sappiamo. Le prime tre linee sono facili; per ognuno di noi:
Per quanto riguarda questa linea:
var allFriends: Array = [firstFriendDetails, secondFriendDetails, thirdFriendDetails];
... avremo bisogno di una corda e del nastro.
Possiamo pensare che una riga sia equivalente a questo frammento:
var allFriends: Array = []; allFriends [0] = firstFriendDetails; allFriends [1] = secondFriendDetails; allFriends [2] = thirdFriendDetails;
La prima riga è semplice: prendi un nuovo raccoglitore e un nuovo post-it, scrivi tutti gli amici
sul post-it, e incollalo al raccoglitore.
Per quanto riguarda la seconda linea:
allFriends [0] = firstFriendDetails;
Ricorda che ho detto che ogni pagina di un raccoglitore è come una nota post-it, ad eccezione di ciò che è scritto a penna. Se la prima pagina fosse un post-it, dovremmo semplicemente inserirla nella parte anteriore del firstFriendDetails
legatore, giusto?
... ma non può essere sia sulla parte anteriore di quel raccoglitore e all'interno dell'altro raccoglitore. Quindi, invece, usiamo la stringa:
Lo stesso per gli altri due:
Quindi quando vogliamo sapere cosa allFriends [2]
si riferisce a, abbiamo solo aperto il tutti gli amici
legare a quella pagina e seguire la stringa - che, naturalmente, porta al thirdFriendDetails
legante.
Allo stesso modo, per allFriends [1] [0]
, per prima cosa scopriamo quale raccoglitore allFriends [1]
si riferisce a, e quindi guardiamo la prima pagina di quello legatore ... così allFriends [1] [0]
è Marty
!
Ora metti insieme tutte queste informazioni e tienilo presente quando leggi questo frammento:
amici vari: 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);
Cosa succede se modifichiamo il valore di currentFriend
all'interno del ciclo?
amici vari: 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]);
Cosa fare se l'array contiene oggetti non primitivi (MovieClip, immagini, matrici, oggetti 3D, qualsiasi cosa)?
var friends: Array = [firstFriend, secondFriend, thirdFriend, fourthFriend, fifthFriend]; var currentIndex: int = 0; var currentFriend: MovieClip; // o ": Immagine" o ": Oggetto" o ": Array" o qualsiasi altra cosa (currentIndex < 5) currentFriend = friends[currentIndex]; currentFriend = sixthFriend; //What is the value of friends[0] now?
Infine, cosa succede se la matrice contiene altri array, che a loro volta contengono primitive?
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];
Cosa ne pensi del valore di amici [3] [0]
sarà dopo?
Ecco alcune altre note importanti che dovresti sapere:
In AS3 e JavaScript, gli oggetti sono come matrici ad eccezione di ogni pagina a cui fa riferimento un'etichetta piuttosto che il suo numero di pagina. Quindi puoi digitare:
var detailsOfBill: Object = ; // "" significa "crea un oggetto" detailsOfBill.title = "Esquire"; detailsOfBill.bandName = "Wyld Stallyns"; detailsOfBill.allNames = ["Bill", "S.", "Preston"];
… e questo è tipo come ottenere un nuovo raccoglitore, attaccare un detailsOfBill
Post-it sul davanti e riempiendolo con tre pagine. La prima pagina ha l'etichetta titolo
scritto in alto nella penna e nella parola scudiero
scritto su di esso a matita; la seconda pagina ha l'etichetta bandName
a penna e Wyld Stallyns
a matita. La terza pagina ha l'etichetta allNames
ma non ha scritto nulla a matita; invece, una stringa lo allega a un altro raccoglitore regolare, le cui pagine non sono etichettate: la prima pagina dice Conto
, il secondo dice S.
, e il terzo dice Preston
, tutto a matita.
(Per rendere le cose ancora più confuse, gli array sono tecnicamente una forma speciale di Object. E se pensi che sia male, le funzioni possono essere viste anche come un tipo di Oggetto! Ma questo è un argomento per un futuro articolo ...)
Ho detto che gli oggetti sono spazzatura raccolti se non hanno alcun Post-it su di loro, ma questa è una semplificazione eccessiva. Se una pagina di un raccoglitore punta a un oggetto tramite una stringa (ad esempio, se myArray [0] = myObject
o simili), quindi quell'oggetto non sarà raccolto. Lo stesso vale se una pagina di un raccoglitore punta a un altro raccoglitore (matrice) o se la pagina di un raccoglitore di oggetti punta a un altro raccoglitore di oggetti ... e così via. Si applica anche se l'unico modo per accedere all'oggetto è attraverso un post-it attaccato a un raccoglitore che ha una pagina che è legata a un altro raccoglitore, come molti strati in profondità come vuoi andare.
Fondamentalmente, il garbage collector raccoglie un oggetto solo se non può essere raggiunto attraverso altre variabili.
Questo spiega perché gli oggetti che sono sullo schermo di solito non possono essere oggetto di raccolta. In AS3, se un MovieClip o un altro tipo di DisplayObject si trova nell'elenco di visualizzazione, viene automaticamente aggiunto a ciò che è essenzialmente una matrice nascosta di oggetti di visualizzazione (a cui è possibile accedere tramite getChildAt ()). Strutture simili esistono in JavaScript e C #. Quindi se un grafico è sullo schermo e rimuovi tutti i riferimenti ad esso da variabili, matrici e oggetti, non sarà ancora raccolto in modo automatico finché non lo rimuovi dall'elenco di visualizzazione.
Spero che questo aiuti a chiarire le cose. È certamente un concetto confuso quando lo si incontra per la prima volta: alcune variabili contengono effettivamente a valore, mentre altri contengono solo a riferimento a un oggetto. Non preoccuparti se non sei sicuro al 100% esattamente di quello che sta succedendo; avrà molto più senso dopo un po 'di pratica (e qualche errore!).
Tuttavia, se hai domande specifiche su questo argomento, metti un commento qui sotto e farò del mio meglio per rispondere.
Grazie per aver letto!