views:

73

answers:

2

Hi! I have the following problem with .push() method:

var myArray = ["a", "b", "c", "d"];

function add(arr) {
    arr.push("e");
    return arr;
}

add(myArray);

// myArray is now  ["a", "b", "c", "d", "e"]

Why it overrides myArray? Can't understand that...

+8  A: 

Arrays in Javascript (and most other languages) are passed by reference.

When you write add(myArray), you are passing a reference to the same Array instance that the global myArray variable refers to.
Any changes to the array object will be visible through both references.

To copy the actual array instance, write add(myArray.slice());.
Note that this will not copy the objects inside of it.

SLaks
Is there a simple way how to avoid that?
Jany
@Jany: you can't force an array to be passed by value - you'll have to copy it and then pass the copy as a reference, exactly as SLaks demonstrates.
BoltClock
You can pass a copy of the array by writing `add(myArray.slice());`
SLaks
I think using slice method is very simple.
Zafer
Thank you all!!!
Jany
But if I write inside function `arr = "";`, `myArray` doesn't change. It hapens only with methods?
Jany
@Jany: By writing `arr = ""`, you are re-assigning the _variable_ to refer to a new instance. That does not affect the original Array instance that `arr` used to refer to.
SLaks
+2  A: 

If you need to be able to nest arrays, then I'd change the .add() function to have the .concat() duplicate the Array into a variable, .push() the new value into the new Array, and return it.

function add(arr) {
    var newArr = arr.concat(); // duplicate
    newArr.push("e");      // push new value
    return newArr;         // return new (modified) Array
}

You could use concat() as well, and return the new array it creates.

var myArray = ["a", "b", "c", "d"];

function add(arr) {
    return arr.concat("e");
}
var newArray = add(myArray);

console.log( newArray );  // ["a", "b", "c", "d", "e"]
console.log( myArray );   // ["a", "b", "c", "d"]

So instead of two methods .slice() then .push(), you accomplish it with one .concat().

This also gives you the benefit of passing another Array instead of a string, so:

return arr.concat(["e","f"]);

would give you:

// ["a", "b", "c", "d", "e", "f"]

instead of:

// ["a", "b", "c", "d", ["e", "f"] ]
patrick dw
+1 - a clean solution
Russ Cam
This is nice, thanks! But I need to put another array into... This doesn't work :( `arr.concat([["e","f"]]);`
Jany
@Jany - I updated my answer to `.push()` the value into the duplicate. You just pass the original Array into `.add()`, and it takes care of the duplication inside. This way, inside the `.add()` you have access to *both* Arrays, old and new.
patrick dw