I don't understand the assignment operator when assigning objects (say, arrays). I'm told that as assignment operator copies the reference. However it seems like it copies the data. For example:
var globArray = [];
function test() {
var names = ["craig", "silva"];
globArray = names;
}//endFunction test
function test2() {
console.log("el1: ", globArray[0], "el2: ", globArray[1]);
}//endFunction test2
When I call TEST, it creates array NAMES and assigns the global array "globArray" to NAMES. Now it goes out of scope, so "names" is gone, right? Then later I call test2, but it DOES show the elements! So it must have COPIED the whole object, as opposed to just coping the reference.
Can someone explain this?
I don't understand the assignment operator when assigning objects (say, arrays). I'm told that as assignment operator copies the reference. However it seems like it copies the data. For example:
var globArray = [];
function test() {
var names = ["craig", "silva"];
globArray = names;
}//endFunction test
function test2() {
console.log("el1: ", globArray[0], "el2: ", globArray[1]);
}//endFunction test2
When I call TEST, it creates array NAMES and assigns the global array "globArray" to NAMES. Now it goes out of scope, so "names" is gone, right? Then later I call test2, but it DOES show the elements! So it must have COPIED the whole object, as opposed to just coping the reference.
Can someone explain this?
Share Improve this question asked Oct 24, 2012 at 13:28 mungemunge 731 silver badge12 bronze badges 2- 1 If you think this is confusing, wait until you see closures. – SLaks Commented Oct 24, 2012 at 13:31
-
1
globArray = names;
copies the reference to the array. After this statement, the array is referenced by bothnames
, andglobArray
. – Šime Vidas Commented Oct 24, 2012 at 13:32
5 Answers
Reset to default 6When your "test" function returns, you're correct that "names" is "gone". However, its value is not, because it's been assigned to a global variable. The value of the "names" local variable was a reference to an array object. That reference was copied into the global variable, so now that global variable also contains a reference to the array object.
Object allocation is a global thing. When an object is allocated and referenced by a local variable, then it will be garbage-collected when the local variable disappears when its scope bees inactive unless some other reference (direct or indirect) to the object exists. A direct reference would be a case like yours. An indirect reference can happen if the local scope "leaks" a function that includes a reference to the local variable.
There are two things at play here : activation records, and objects on the heap.
You start off with an activation frame for global variables:
globArray : undefined
and the heap contains literals that appear in your code
ptr0 : "craig"
ptr1 : "silva"
where ptr0
, ptr1
, etc. are just addresses or labels that refer to a particular location in memory.
When you call test()
, the interpreter pushes a new activation frame which contains boxes for local variables.
globArray : undefined
---------------------
names : undefined
Then the interpreter evaluates ["craig", "silva"]
which creates an object on the heap.
ptr0 : "craig"
ptr1 : "silva"
ptr2 : [ &ptr0, &ptr1 ]
so ptr2
now is a location in memory containing an array that points to two values.
This memory location is now stored in the names
location in the activation record, so your call stack looks like
globArray : undefined
---------------------
names : &ptr2
The assignment names = ...
does not change the heap, just the activation record.
Next globArray = names
copies the contents of one activation record entry to another.
globArray : &ptr2
---------------------
names : &ptr2
Then the call to test
ends so that activation record is discarded, leaving
globArray : &ptr2
where the global globArray
points to the object created during the call to test
.
The end of the function just changes the active activation records, not the heap, so the heap still looks like
ptr0 : "craig"
ptr1 : "silva"
ptr2 : [ &ptr0, &ptr1 ]
so ptr2
is still the same array.
so "names" is gone, right?
names
(the entry in the activation record) is gone, but the object it pointed to is not since it is still pointed to by the globArray
entry in an active activation record.
Then later I call test2, but it DOES show the elements! So it must have COPIED the whole object
No, it just copied a reference to the location in the heap occupied by that object. No new object was created since the heap was not changed, and the heap is where all objects are created.
What and where are the stack and heap? might be of interest.
Both names and globalArray refer to the same object. This object will not 'go away' as long as there is at least one reference to it in scope. You know what did go away? The initial array globalArray referred to.
Javascript objects are garbage-collected.
The object referred to by the names
variable will continue to exist after test()
exits, because it's still referenced by the global variable.
The object is separate from the variable that holds a reference to it. Even after the variable is gone, the object may still exist. This is what's happening in your code, even when the names
variable is gone, the object that it referenced still exists independently of the variable name
. Only when there are no references left to the object, it will be removed from memory.
You can verify that the data isn't copied when you assign an object. After you have assigned the object to another variable, you can change the object using the first variable, and it will change when seen using the other variable:
function test() {
var names = ["craig", "silva"];
globArray = names;
names[0] = 'peter';
}
Now when you display the contents of globArray
, you will see peter
and silva
, because both variables have a reference to the same array object.