7

I've got what may be a stupid question. In the code below, the function doStuff appears to reassign myArray to an empty array, but when tried it in the console, myArray is still [2,3,4,5].

var myArray = [2, 3, 4, 5];
function doStuff(arr) {
   arr = [];
};

doStuff(myArray);
console.log(myArray)// => [2,3,4,5]

Further, a function that modifies the array seems to work fine. For example:

 function changeSecondIndex(arr){
      arr[2] = 25;
 }

 changeSecondIndex(myArray)
 console.log(myArray) // => [2,3,25,5]

Could someone please help me understand what's going on here? Thanks.

Andreas
  • 5,305
  • 4
  • 41
  • 60
EFH
  • 431
  • 1
  • 6
  • 14
  • 1
    Possible duplicate of [Javascript passing arrays to functions by value, leaving original array unaltered](http://stackoverflow.com/questions/14491405/javascript-passing-arrays-to-functions-by-value-leaving-original-array-unaltere) – ManoDestra Jun 07 '16 at 20:16
  • 1
    @ManoDestra The question here is `why it happens` and the question in that post is `how to fix it`. Two different questions from my point of view. – Marc Compte Jun 07 '16 at 21:17
  • This question is answered by the other when it is understood. – ManoDestra Jun 07 '16 at 22:15

7 Answers7

4

Your code is creating new empty array, instead you can empty existing array with length = 0

var myArray = [2, 3, 4, 5];
function doStuff(arr) {
   arr.length = 0;
};

doStuff(myArray);
console.log(myArray)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
3

Javacript arrays are passed by reference, which means they can be modified within functions. This is why your second code snippet works.

Your first code snippet, however, simply declares a new variable arr within the scope of the function. It does not overwrite the old variable name, it merely removes your ability to reference the global variable you passed in.

Once that function exits, the new variable arr goes out of scope, and the name binding falls back to the global variable you declared previously.

That's why doStuff() does not modify the original array - because you were actually declaring a brand new array that just happened to share the same name within the scope of the function.

Akshat Mahajan
  • 9,543
  • 4
  • 35
  • 44
  • *Both* functions will contain a variable `arr`. It's the parameter to the function. `doStuff` sets that variable to a value. Nowhere does it declare a new variable. – gen_Eric Jun 07 '16 at 20:23
  • @RocketHazmat No, in the first snippet, the name `arr` is bound to the parameter passed in. In the second snippet, the name `arr` is bound to a new array `[]`, because it's a definition. – Akshat Mahajan Jun 07 '16 at 20:23
  • But both functions are called via `func(myArray)` and both have `arr` in the function signature as a parameter. – gen_Eric Jun 07 '16 at 20:24
  • @RocketHazmat Yes, and this is an example of [variable shadowing](http://stackoverflow.com/questions/11901427/an-example-of-variable-shadowing-in-javascript). The core issue here is that there is no `var` keyword in the local scope, and [that has weird consequences](http://stackoverflow.com/questions/1470488/what-is-the-function-of-the-var-keyword-and-when-to-use-it-or-omit-it). – Akshat Mahajan Jun 07 '16 at 20:27
  • He wants `arr = []` to change the value of `myArray` to a blank array. – gen_Eric Jun 07 '16 at 20:34
  • Then he could return the new `arr` and assign that `arr` to `myArray`. If he wants to modify `myArray` explicitly, he can just do `myArray = [];` in the function - this is resolved to the global array by the scope chain lookup. Either way, fixing this is not the question, and more importantly is entirely a matter of good coding choice :) – Akshat Mahajan Jun 07 '16 at 20:39
  • 1
    I don't so much want to explicitly modify it, I'm just trying to understand *why* it doesn't work in the function – EFH Jun 07 '16 at 20:44
3

Arrays are passed by reference in JavaScript. So, in your doStuff and changeSecondIndex functions, the arr parameter contains a reference to myArray.

In changeSecondIndex, you're using that reference to access and update a property of the array. That works fine, as you can see. But in doStuff, what's actually happening is that you are setting arr to a new array. What that does is remove the fact that arr was a reference to myArray and sets it to a new blank array. That's why myArray is not modified.

gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • 1
    When I visualize doStuff working, I see this: `doStuff(myArray) { myArray = []} ` But you're saying that myArray within the doStuff function is not the same as the global var myArray? – EFH Jun 07 '16 at 20:29
  • `myArray` was being *referenced* in the `doStuff()` function as `arr`. But what happened was that that reference was destroyed. When you did `arr = []`, you're removing the old value of `arr` (a reference) and setting to a new value (`[]`). It may sound weird, but you're setting the *value* of `arr`, not `myArray`. – gen_Eric Jun 07 '16 at 20:33
  • 1
    I'd bet that could cause some really confusing bugs. Maybe I haven't been bitten by this (yet?) because I try to use functions to return values, instead of changing them in-place. Something like this: function changeSecondIndex(arr) { arr[1] = 25; return arr; } myArray = changeSecondIndex(myArray); ..which wouldn't allow the issue at all. Not that I'm so great; I got this from [elsewhere](https://en.wikipedia.org/wiki/Functional_programming), of course. I'm just glad to see it paying off in ways I may not even have noticed. – Jon Carter Jun 07 '16 at 20:37
2

Objects are passed by reference in JavaScript, when you call the function in your first example the parameter arr is a reference to the object that is passed when the function is invoked

var myArray = [2, 3, 4, 5];
function doStuff(arr) {
   //arr is a variable that contains the first parameter used to invoke the 
   //function, if the variable is an object then it is passed by reference
   //
   //Here you are assigning the variable "arr" the value of a new array
   arr = [];
};

doStuff(myArray);
console.log(myArray)// => [2,3,4,5]

In the second example you are modifying the passed object, everything is still being passed the same way, difference is you are acting on the object that was passed rather than assigning the variable a new value.

 function changeSecondIndex(arr){
      //Acting on index 2 of the passed array and setting the value to 25
      arr[2] = 25;
 }

 changeSecondIndex(myArray)
 console.log(myArray) // => [2,3,25,5]

If you wanted to do something similar to what you are trying to do in the first example could have some sort of object that contains a state with your variables in it

var workingVars= {arr: [2, 3, 4, 5]};
function doStuff(env) {
   // here you are assigning a new empty array to arr property of 
   // passed parameter
   env.arr = [];
};
doStuff(workingVars);
console.log(workingVars.arr)// => []
konkked
  • 3,161
  • 14
  • 19
1

You don't need a function and arguments to experiment this. In JS [] and {} are object creation patterns (literal) and breaks the referral. Let's see...

var a = [1,2];
var b = [2,4];
var c = a; // c references a array.
var d = b; // d references b array
a.length = 0; // a becomes []
b = []; // b becomes []
console.log(c); // [] c still references a
console.log(d); // [2,4] d is no more a reference to b

Of course the same applies to the objects;

var o1 = {x:1, y:2};
var o2 = {x:2, y:4};
var p1 = o1; // p1 references o1
var p2 = o2; // p2 references o2
delete o1.x;
delete o1.y;
console.log(o1); // Object {}
console.log(p1); // Object {} p1 still references o1
o2 = {};
console.log(o2); // Object {}
console.log(p2); // Object {x: 2, y: 4} p2 is no more a reference to o2
Redu
  • 25,060
  • 6
  • 56
  • 76
0

To understand why this is happening you must first remember that an Array in Javascript is an object . The reason your arr = [] is taking no affect on your global declaration is for the following :

Reason 1 :

arr = [] does not clear an array , it just creates a new array object in memory no matter what .

So in your function :

function doStuff(arr) {
   arr = [];
};

doStuff(myArray)

you are just taking in myArray and making a new empty version of it in a local scope which leads to reason 2 .

Reason 2 :

Any new object / variable declared in a function is confined to the local scope of that function

so :

function doStuff(arr) {
   arr = [];
};


doStuff(myArray) //logs [1,2,3,4]

arr = [] was destroyed at the closing bracket of doStuff function an cannot exist on the outside .

Reason 3 :

function doStuff(arr){

 arr[2] = 25;

}

doStuff(myArray)

This works because you're accessing myArray in arr variable and modifying a property off myArray object, this is perfectly normal in javascript.

In short : = operator assigns , re-assigns , and creates ...

arr = [] is an assignment to new myArray object within your function and is also trapped in the scope of your function .

arr[2] = 25 accesses myArray object temporarily and re-assigns a property .

Hope this helps..

KpTheConstructor
  • 3,153
  • 1
  • 14
  • 22
-4

You have defined global var myArray. And then you want to access this global array and change it in function. Yes it will overwrite global array, but only when you specific function. in your case function doStuff().

If you don't call doStuff(), it will keep global inicialization values!

swipeales
  • 127
  • 1
  • 2
  • 12