1

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?

munge
  • 73
  • 1
  • 12
  • 1
    If you think this is confusing, wait until you see closures. – SLaks Oct 24 '12 at 13:31
  • 1
    `globArray = names;` copies the reference to the array. After this statement, the array is referenced by both `names`, and `globArray`. – Šime Vidas Oct 24 '12 at 13:32

5 Answers5

6

When 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 becomes 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.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • +1 `An indirect reference can happen if the local scope "leaks" a function that includes a reference to the local variable` - as seen in hundreds of questions about ajax handlers in loops referring to the final counter value. – Asad Saeeduddin Oct 24 '12 at 13:37
  • @Asad yes, exactly :-) It's a significant fraction of Stackoverflow content! – Pointy Oct 24 '12 at 14:07
3

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.

Community
  • 1
  • 1
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • This is what a good SO answer should be: technically correct and easy to understand at the same time. – georg Oct 24 '12 at 15:15
2

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.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
2

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.

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
0

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.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005