-
Notifications
You must be signed in to change notification settings - Fork 57
Object references and copying #182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
351b8dc
edb34f4
3a04245
8f57c2a
142ab5f
cd6de5c
9ad65ff
a6c961a
bc95b87
e94e662
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,116 +1,118 @@ | ||
# Object references and copying | ||
# Oggetti: riferimento e copia | ||
|
||
One of the fundamental differences of objects versus primitives is that objects are stored and copied "by reference", whereas primitive values: strings, numbers, booleans, etc -- are always copied "as a whole value". | ||
Una delle maggiori differenze tra oggetti e primitivi è che gli oggetti vengono memorizzati e copiati "per riferimento", mentre i primitivi (stringhe, numeri, booleani, ecc...) vengono sempre copiati "per valore". | ||
|
||
That's easy to understand if we look a bit under the hood of what happens when we copy a value. | ||
Questa differenza è facile da comprendere se andiamo a guardare il comportamento del linguaggio quando copiamo un valore. | ||
|
||
Let's start with a primitive, such as a string. | ||
Partiamo con un primitivo, ad esempio una stringa. | ||
|
||
Here we put a copy of `message` into `phrase`: | ||
Qui facciamo una copia di `message` in `phrase`: | ||
|
||
```js | ||
let message = "Hello!"; | ||
let phrase = message; | ||
``` | ||
|
||
As a result we have two independent variables, each one storing the string `"Hello!"`. | ||
Come risultato otteniamo due variabili distinte, ognuna delle quali contiene la stringa `"Hello!"`. | ||
|
||
 | ||
|
||
Quite an obvious result, right? | ||
E' un risultato abbastanza ovvio, giusto? | ||
|
||
Objects are not like that. | ||
Gli oggetti non funzionano allo stesso modo. | ||
|
||
**A variable assigned to an object stores not the object itself, but its "address in memory" -- in other words "a reference" to it.** | ||
**Una variabile assegnata ad un oggetto non contiene l'oggetto in sé, ma il suo "indirizzo in memoria" -- in altre parole "un riferimento" all'oggetto.** | ||
|
||
Let's look at an example of such a variable: | ||
Diamo un'occhiata a un esempio di tale variabile: | ||
|
||
```js | ||
let user = { | ||
name: "John" | ||
}; | ||
``` | ||
|
||
And here's how it's actually stored in memory: | ||
Ed ecco come viene effettivamente archiviata in memoria: | ||
|
||
 | ||
|
||
The object is stored somewhere in memory (at the right of the picture), while the `user` variable (at the left) has a "reference" to it. | ||
L'oggetto è archiviato da qualche parte nella memoria (a destra nell'immagine), mentre la variabile `user` (a sinistra) contiene il "riferimento" ad esso. | ||
|
||
We may think of an object variable, such as `user`, as like a sheet of paper with the address of the object on it. | ||
Potremmo immaginare la "variabile oggetto" `user`, come un foglio di carta con scritto l'indirizzo dell'oggetto. | ||
|
||
When we perform actions with the object, e.g. take a property `user.name`, the JavaScript engine looks at what's at that address and performs the operation on the actual object. | ||
Quando eseguiamo azioni con l'oggetto, ad es. leggere una proprietà `user.name`, il motore JavaScript guarda cosa c'è a quell'indirizzo ed esegue l'operazione sull'oggetto reale. | ||
|
||
Now here's why it's important. | ||
Ecco perché è così importante. | ||
|
||
**When an object variable is copied, the reference is copied, but the object itself is not duplicated.** | ||
**Quando una "variabile oggetto" viene copiata, in realtà viene copiato il riferimento, ma l'oggetto in sé non viene duplicato.** | ||
|
||
For instance: | ||
Esempio: | ||
|
||
```js no-beautify | ||
let user = { name: "John" }; | ||
|
||
let admin = user; // copy the reference | ||
let admin = user; // copia il riferimento | ||
``` | ||
|
||
Now we have two variables, each storing a reference to the same object: | ||
Ora abbiamo due variabili, entrambe contengono il riferimento allo stesso oggetto: | ||
|
||
 | ||
|
||
As you can see, there's still one object, but now with two variables that reference it. | ||
Come puoi vedere, l'oggetto è uno solo, ma ora con due variabili che si riferiscono ad esso. | ||
|
||
We can use either variable to access the object and modify its contents: | ||
Possiamo usare entrambe le variabili per accedere all'oggetto e modificarne il contenuto: | ||
|
||
```js run | ||
let user = { name: 'John' }; | ||
|
||
let admin = user; | ||
|
||
*!* | ||
admin.name = 'Pete'; // changed by the "admin" reference | ||
admin.name = 'Pete'; // modificato dal riferimento in "admin" | ||
*/!* | ||
|
||
alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference | ||
alert(*!*user.name*/!*); // 'Pete', le modifiche sono visibili dal riferimento in "user" | ||
``` | ||
|
||
It's as if we had a cabinet with two keys and used one of them (`admin`) to get into it and make changes. Then, if we later use another key (`user`), we are still opening the same cabinet and can access the changed contents. | ||
E' come se avessimo un armadietto con due chiavi e ne usassimo una (`admin`) per aprirlo ed apportare delle modiche al contenuto. Quindi, successivamente, potremmo aprire lo stesso armadietto con un'altra chiave (`user`) ed accedere al contenuto modificato. | ||
|
||
## Comparison by reference | ||
## Confronto per riferimento | ||
|
||
Two objects are equal only if they are the same object. | ||
Due oggetti sono uguali solo se sono lo stesso oggetto. Suona un po' strano, ma ora chiariremo. | ||
|
||
For instance, here `a` and `b` reference the same object, thus they are equal: | ||
Qui `a` e `b` si riferiscono allo stesso oggetto, quindi sono uguali: | ||
|
||
```js run | ||
let a = {}; | ||
let b = a; // copy the reference | ||
let b = a; // copia il riferimento | ||
|
||
alert( a == b ); // true, both variables reference the same object | ||
alert( a == b ); // true, entrambe le variabili si riferiscono allo stesso oggetto | ||
alert( a === b ); // true | ||
``` | ||
|
||
And here two independent objects are not equal, even though they look alike (both are empty): | ||
Qui, invece, due oggetti identici (entrambi vuoti), ma indipendenti, non soddisfano l'uguaglianza: | ||
|
||
|
||
```js run | ||
let a = {}; | ||
let b = {}; // two independent objects | ||
let b = {}; // due oggetti indipendenti | ||
|
||
alert( a == b ); // false | ||
``` | ||
|
||
For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are needed very rarely -- usually they appear as a result of a programming mistake. | ||
Per confronti tra oggetti (Es. `obj1 > obj2`) o con primitivi (Es. `obj == 5`), gli oggetti vengono convertiti in primitivi. Vedremo molto presto come avviene questa conversione, anche se, a dire il vero, questo tipo di confronto è molto raro e generalmente è il risultato di un errore di programmazione. | ||
|
||
## Cloning and merging, Object.assign | ||
## Clonazione e unione, Object.assign | ||
|
||
So, copying an object variable creates one more reference to the same object. | ||
Come abbiamo detto, copiare una "variabile oggetto" crea un ulteriore riferimento allo stesso oggetto. | ||
|
||
But what if we need to duplicate an object? Create an independent copy, a clone? | ||
Quindi, come possiamo fare se abbiamo bisogno di duplicare un oggetto? Creare una copia indipendente, un clone? | ||
|
||
That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. But there is rarely a need -- copying by reference is good most of the time. | ||
Anche questo è fattibile, ma con un po' di difficoltà visto che JavaScript non ha alcun metodo integrato per farlo. In realtà non è un'operazione frequente, il più delle volte la copia per riferimento è adatta alla situazione. | ||
|
||
But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level. | ||
Ma se proprio ne abbiamo bisogno, allora dobbiamo creare un nuovo oggetto e replicare la struttura di quello esistente iterando le sue proprietà | ||
e copiandole a livello primitivo. | ||
|
||
Like this: | ||
Così: | ||
|
||
```js run | ||
let user = { | ||
|
@@ -119,59 +121,60 @@ let user = { | |
}; | ||
|
||
*!* | ||
let clone = {}; // the new empty object | ||
let clone = {}; // il nuovo oggetto vuoto | ||
|
||
// let's copy all user properties into it | ||
// copiamo nella variabile clone tutte le proprietà di user | ||
for (let key in user) { | ||
clone[key] = user[key]; | ||
} | ||
*/!* | ||
|
||
// now clone is a fully independent object with the same content | ||
clone.name = "Pete"; // changed the data in it | ||
// ora clone è un oggetto completamente indipendente ma con lo stesso contenuto di user | ||
clone.name = "Pete"; // cambiamo la proprietà name | ||
|
||
alert( user.name ); // still John in the original object | ||
alert( user.name ); // nell'oggetto originale è rimasto "John" | ||
``` | ||
|
||
Also we can use the method [Object.assign](mdn:js/Object/assign) for that. | ||
Possiamo anche usare il metodo [Object.assign](mdn:js/Object/assign) . | ||
|
||
The syntax is: | ||
La sintassi è: | ||
|
||
```js | ||
Object.assign(dest, [src1, src2, src3...]) | ||
``` | ||
|
||
- The first argument `dest` is a target object. | ||
- Further arguments `src1, ..., srcN` (can be as many as needed) are source objects. | ||
- It copies the properties of all source objects `src1, ..., srcN` into the target `dest`. In other words, properties of all arguments starting from the second are copied into the first object. | ||
- The call returns `dest`. | ||
- Il primo argomento `dest` è l'oggetto di destinazione. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Non mi convince moltissimo di destinazione. Sarebbe piu' chiaro, magari, se aggiungessimo 'delle proprieta' da copiare'. (Nemmeno i sinonimi mi convincono molto; dalla treccani: finalità, fine, meta, mira, obiettivo, scopo, target, traguardo; forse "l'oggetto di mira"?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. piu' letteralmente "target" sarebbe "obiettivo", ma in questo caso "destinazione" mi sembra renda meglio l'idea |
||
- Gli argomenti successivi `src1, ..., srcN` (possono essere quanti vogliamo) sono gli oggetti da copiare. | ||
- Il metodo copia tutte le proprietà degli oggetti `src1, ..., srcN` in quello di destinazione `dest`. | ||
- Viene restituito l'oggetto `dest`. | ||
|
||
Per fare un esempio, possiamo unire diversi oggetti in uno solo: | ||
|
||
For instance, we can use it to merge several objects into one: | ||
```js | ||
let user = { name: "John" }; | ||
|
||
let permissions1 = { canView: true }; | ||
let permissions2 = { canEdit: true }; | ||
|
||
*!* | ||
// copies all properties from permissions1 and permissions2 into user | ||
// copia tutte le proprietà da permissions1 e permissions2 in user | ||
Object.assign(user, permissions1, permissions2); | ||
*/!* | ||
|
||
// now user = { name: "John", canView: true, canEdit: true } | ||
// ora user = { name: "John", canView: true, canEdit: true } | ||
``` | ||
|
||
If the copied property name already exists, it gets overwritten: | ||
Se una delle proprietà copiate è già presente nell'oggetto di destinazione, verrà sovrascritta. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Vedi sopra (anche se, ti diro', qui e' intuitivo) |
||
|
||
```js run | ||
let user = { name: "John" }; | ||
|
||
Object.assign(user, { name: "Pete" }); | ||
|
||
alert(user.name); // now user = { name: "Pete" } | ||
alert(user.name); // ora user = { name: "Pete" } | ||
``` | ||
|
||
We also can use `Object.assign` to replace `for..in` loop for simple cloning: | ||
Possiamo anche usare `Object.assign` per sostituire il ciclo `for..in` nella clonazione semplice: | ||
|
||
```js | ||
let user = { | ||
|
@@ -184,13 +187,14 @@ let clone = Object.assign({}, user); | |
*/!* | ||
``` | ||
|
||
It copies all properties of `user` into the empty object and returns it. | ||
Vengono copiate tutte le proprietà di `user` nell'oggetto vuoto, il quale, poi, viene restituito. | ||
|
||
## Clonazione nidificata | ||
|
||
## Nested cloning | ||
Finora abbiamo assunto che le proprietà di `user` fossero primitive. Ma le proprietà possono anche essere riferimenti ad altri oggetti. Come si fa in questo caso? | ||
|
||
Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. What to do with them? | ||
Così: | ||
|
||
Like this: | ||
```js run | ||
let user = { | ||
name: "John", | ||
|
@@ -203,9 +207,9 @@ let user = { | |
alert( user.sizes.height ); // 182 | ||
``` | ||
|
||
Now it's not enough to copy `clone.sizes = user.sizes`, because the `user.sizes` is an object, it will be copied by reference. So `clone` and `user` will share the same sizes: | ||
In questo caso non è sufficiente copiare `clone.sizes = user.sizes`. Siccome `user.sizes` è un oggetto, verrà copiato per riferimento. Quindi `clone` e `user` condivideranno lo stesso oggetto "sizes". | ||
|
||
Like this: | ||
Vediamo un esempio: | ||
|
||
```js run | ||
let user = { | ||
|
@@ -218,21 +222,21 @@ let user = { | |
|
||
let clone = Object.assign({}, user); | ||
|
||
alert( user.sizes === clone.sizes ); // true, same object | ||
alert( user.sizes === clone.sizes ); // true, è lo stesso oggetto | ||
|
||
// user and clone share sizes | ||
user.sizes.width++; // change a property from one place | ||
alert(clone.sizes.width); // 51, see the result from the other one | ||
// user e clone condividono sizes | ||
user.sizes.width++; // cambiamo una proprietà da una parte | ||
alert(clone.sizes.width); // 51, e vediamo il risultato dall'altra | ||
``` | ||
|
||
To fix that, we should use a cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning". | ||
Per risolvere questo problema, dobbiamo usare un ciclo di clonazioni che esaminerà ogni valore di `user[key]` e, nel caso sia un oggetto, replichi anche la sua struttura. Questa operazione è chiamata "deep cloning" (copia profonda). | ||
|
||
We can use recursion to implement it. Or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com). | ||
Per implementare questa funzione possiamo usare la ricorsione. Oppure, per non reinventare la ruota, possiamo usare qualcosa di già pronto, ad esempio [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) dalla libreria JavaScript [lodash](https://lodash.com). | ||
|
||
````smart header="Const objects can be modified" | ||
An important side effect of storing objects as references is that an object declared as `const` *can* be modified. | ||
````smart header="Gli oggetti dichiarati con const possono essere modificati" | ||
Un importante "side effect" della memorizzazione per riferimento è che un oggetto dichiarato con `const` *può* essere modificato. | ||
|
||
For instance: | ||
Esempio: | ||
|
||
```js run | ||
const user = { | ||
|
@@ -246,17 +250,17 @@ user.name = "Pete"; // (*) | |
alert(user.name); // Pete | ||
``` | ||
|
||
It might seem that the line `(*)` would cause an error, but it does not. The value of `user` is constant, it must always reference the same object, but properties of that object are free to change. | ||
Saremmo portati a pensare che la linea `(*)` causi un errore, ma non è così. Il valore di `user` è costante, si riferisce sempre allo stesso oggetto, ma le proprietà dell'oggetto sono libere di cambiare. | ||
|
||
In other words, the `const user` gives an error only if we try to set `user=...` as a whole. | ||
In altre parole, `const user` restituisce un errore solo se se proviamo a riassegnare in toto `user=...`. | ||
|
||
That said, if we really need to make constant object properties, it's also possible, but using totally different methods. We'll mention that in the chapter <info:property-descriptors>. | ||
Detto questo, se vogliamo veramente rendere invariabili le proprietà di un oggetto, possiamo farlo, ma con un metodo totalmente differente. Ne parleremo nel capitolo <info:property-descriptors>. | ||
```` | ||
|
||
## Summary | ||
## Riepilogo | ||
|
||
Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object itself. | ||
Gli oggetti sono assegnati e copiati per riferimento. In altre parole una variabile non contiene il "valore oggetto" ma un "riferimento" (indirizzo in memoria) di quel valore. Quindi copiando tale variabile o passandola come argomento di una funzione si copia quel riferimento, non l'oggetto stesso. | ||
|
||
All operations via copied references (like adding/removing properties) are performed on the same single object. | ||
Tutte le operazioni su un riferimento duplicato (come aggiungere o rimuovere proprietà) hanno effetto sul medesimo oggetto. | ||
|
||
To make a "real copy" (a clone) we can use `Object.assign` for the so-called "shallow copy" (nested objects are copied by reference) or a "deep cloning" function, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). | ||
Per creare una "vera copia" (clonare) effettuare una cosiddetta "shallow copy" (copia superficiale) con `Object.assign`(gli oggetti nidificati vengo copiati per riferimento), oppure un "deep cloning" (copia profonda) con funzioni tipo [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). |
Uh oh!
There was an error while loading. Please reload this page.