2

According to this question, if I pass a global variable as an argument to a function, that global becomes a local copy.

If that is the case, why does this jfiddle behave the way it does? Shouldn't the alert show dog, cat and not just cat?

I even went one further step than the example and specifically copied the global variable into a local variable, but the result is the same. I'd really like to be able to shift() the local while keeping the global intact.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
crowhill
  • 2,398
  • 3
  • 26
  • 55

2 Answers2

6

JavaScript only has pass-by-value. I just wanted to make it clear from the beginning.

To keep things simple, the code below illustrates the difference between pass-by-value and pass-by-reference.

Pass-by-value

function change (x) { x = 7; }

var x = 1;
change(x);
console.log(x); // 1

Pass-by-reference (not available in JavaScript)

function change (x) { x = 7; }

var x = 1;
change(x);
console.log(x); // 7

Now, you need to understand that some types are allocated on the heap, while others are allocated on the stack. So what does that mean?

Well, let's suppose you have a variable.

var x = 5;

Here the value lives on the stack. Which means, if I do

var y = x;

I will have two variables on the stack, both with their own copy of 5. Simple types are always allocated on the stack.

Objects, on the other hand, live on the heap. When I do,

var o1 = {x: 5};

the object will be allocated on the heap, but the value within o1 variable, which is a reference to the object in the heap (let's call #ref1 the value within o1 variable), will be allocated on the stack. Which means, if I do

var o2 = o1;

I will have two variables on the stack, both with their own copy of #ref1, but only one object allocated on the heap.

Now, you can use the reference to access object's members, and because both o1 and o2 contain a reference to the same object, they will be able to locate the object in the heap an change it's x value. If, however, I do the following

o2 = {x: 7};

this will change the value stored on the stack for the variable o2 (will call the new value #ref2). Now, there are two objects on the heap and two references stored on the stack.

Finally, let's talk about your problem:

// The array (which is an object) is allocated on the heap
// {animals} variable will contain a reference to that object (#ref1)
var animals = ["dog", "cat"];

// Pass-by-value
pushSearchList(animals);

// Local variable {passedAnimals} will contain a copy of #ref1,
// but both {passedAnimals} and {animals} can modify the same object
function pushSearchList(passedAnimals){
   var localAnimals = passedAnimals;
   localAnimals.shift();
   alert(animals);
}

Now, what if you want your own copy of the array object? Just clone the array using:

// {arr} will receive reference to a new array allocated on the heap (#ref2)
var arr = passedAnimals.slice(0);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2

Considering this code:

var animals = ["dog", "cat"];

pushSearchList(animals);

function pushSearchList(passedAnimals){
    var localAnimals = passedAnimals;
    localAnimals.shift();
    alert(animals);
}

animals is NOT copied to the function. It is passed by reference. Anything you do to the passedAnimals ARRAY will affect animals as well. If you SET the variale passedAnimals to something else, like a copy of itself (ie. passedAnimals.slice()), then changes to the new array will no longer affect the source. Because array objects can be changed, they are mutable (liable to change).

In contrast, strings on the other hand (though they can look like an array of characters) are immutable (cannot change). If you pass them to a parameter, a copy will be made.

More on passing by value or reference: http://snook.ca/archives/javascript/javascript_pass

James Wilkins
  • 6,836
  • 3
  • 48
  • 73
  • 2
    JS only has pass-by-value –  Apr 21 '15 at 05:41
  • 1
    Not sure what you mean. In fact, JS passed things using handles in the backend, usually as references (like in C#). When all references are gone, the GC collects the space. I should know - I created V8.Net. ;) – James Wilkins Apr 21 '15 at 05:45
  • 1
    Pass by reference is often taken to mean the equivalent of `ref` in C#, for example. JavaScript passes references, but by value. Without talking about implementation details, you can even say everything is passed in the same way – even if primitives are implemented as references (and strings are; copying them would be wasteful), their immutability means you can’t ever tell the difference. – Ry- Apr 21 '15 at 06:39
  • True, but in C#, how many times is `ref` used? Rarely ever in my years of development. To me, reference means just that, to objects, not variables passed using `ref`. – James Wilkins Apr 21 '15 at 07:34