11

Possible Duplicate:
Copying array by value in javascript

i have a funny problem with javascript. i copy an array variable to make modifications on the copy only, then splice the copy to delete an element. however the original array variable is affected by the splice - as if the copy was a 'copy by reference':

window.onload = function() {
  var initial_variable = ['first', 'second', 'third'];
  var copy_initial_variable = initial_variable;
  copy_initial_variable.splice(0, 1);
  alert('initial variable - ' + initial_variable);
};
//output: initial variable - second,third

firstly, is this intentional behaviour for javascript or is it a bug?

and secondly, how can i make a copy of an array and delete an element in the copy but not in the original?

one thing which makes me think that the above may be a javascript bug is that this behaviour only happens with arrays and not with integers. for example:

window.onload = function() {
  var initial_variable = 1;
  var copy_initial_variable = initial_variable;
  copy_initial_variable = 2;
  alert('initial variable - ' + initial_variable);
};
//output: initial variable - 1

if the behaviour were consistent then this ought to output 2 since the assignment would presumably be by reference?

Community
  • 1
  • 1
mulllhausen
  • 4,225
  • 7
  • 49
  • 71

3 Answers3

14

This is in no way a bug, but a very common misunderstanding. Let's see what happens when I say

var a = b;

Integers and other javascript primitives, like floats and booleans, are "assigned by value". Which means that whatever value b has is going to be copied to a. To the computer, it means having the part of memory that b references copied to the memory that a references. That's the behavior you were expecting.

When arrays and other objects (and "descendants" of a new Object() call) are used like that, there is a copy by reference. Meaning that the value of a now references the value of b, the memory that b references isn't copied or modified. Thus, when writing

a = [1,2,3];
b = a;

b and a become interchangeable. They're referencing the same memory address. To achieve what you're trying to do, use

var copy_initial_variable = initial_variable.slice(0);

Read Does JavaScript pass by reference? for more information.

Community
  • 1
  • 1
FRD
  • 2,254
  • 3
  • 19
  • 24
  • Given that numbers are immutable, how can you tell that they're copied by value and not by reference? In Javascript everything is copied by reference, simply with immutable objects like strings or numbers you cannot tell the difference from a copy by value. – 6502 Jan 05 '13 at 09:21
  • Well, given that numbers are immutable, how can you tell that they're copied by reference and not by value? – FRD Jan 05 '13 at 09:45
  • Exactly. If you cannot tell the difference then why introducing a differentiation between native types and objects about copying/passing when the two categories behave the same? The logical model should be as simple as possible (but not simpler, of course). The distinction you are making here is however pointless. – 6502 Jan 05 '13 at 10:19
  • Simply because it's not the similarities the OP is looking for. Should I be saying that, although variables in javascript MIGHT all be seen as copied by reference, there's a property of objects called immutability, which states that such object cannot have its value altered (which, I'll have to point out later, doesn't mean the variable can't be reassigned) and when assigning to such objects, the runtime may or may not make the variables share a common memory address before they are reassigned to something else etc etc? – FRD Jan 05 '13 at 10:49
  • Besides, either way we are introducing a differentiation between native types and objects: by talking about value/reference assigning or by explaining mutability vs immutability - since no object can be immutable and there's no mutable native type. I don't see the latter being anyhow simpler or having a mandatory precedence over the former approach. That's just another way of seeing things, both of them implementation-dependent. – FRD Jan 05 '13 at 10:59
  • 1
    For someone now, who like 6502 or FRD five years ago, can't prove that numbers copy by value and arrays copy by reference: Try `let a = 1; let b = a; b = 2; console.log("a = " + a + " b = " + b)` and `let c = [1]; let d = c; d[0] = 2; console.log("c = [" + c + "] d = [" + d + "]")` See it now? – BaldEagle Dec 25 '17 at 14:55
4

In first case you are working with arrays, which are passed by reference. And in second case you are working with prime types which are passed by value. In first case you should copy initial array (e.g. with initial_variable.slice(0)). Try something like

window.onload = function() {
  var initial_variable = ['first', 'second', 'third'];
  var copy_initial_variable = initial_variable.slice(0); //returns new array!!!!
  copy_initial_variable.splice(0, 1);
  alert('initial variable - ' + initial_variable);
};
Eugeny89
  • 3,797
  • 7
  • 51
  • 98
0

The problem isn't in how splice behaves, but the fact that initial_variable and copy_initial_variable reference the same array.

alert (copy_initial_variable === initial_variable);

In JavaScript there are two types of values: primitive values, like numbers and booleans, and objects, including arrays. Variables hold primitive values, but they hold references to objects. "Copying" primitive values works as you expect, a new primitive value is created so that changing the copy variable will not change the original variable. But "copying" an object actually copies the reference pointing to that object, it doesn't create a new object.

It is not a JavaScript bug, this is the intended behavior.

Sergiu Dumitriu
  • 11,455
  • 3
  • 39
  • 62
  • True, but the code example doesn't prove anything: `var a = 1; var b = a; alert( a === b );`. – JJJ Jan 05 '13 at 08:57
  • @Juhana Neither does yours, it should be `b = 1` to try to make your point. But try this: `var a = [1], b = [1]; alert(a === b);`. I think his point is well made. – ErikE Jan 05 '13 at 09:04
  • Primitive values are immutable. How can you tell that they're not also passed and copied by reference like objects? – 6502 Jan 05 '13 at 09:24
  • @6502 I don't understand. Are you asking how can I be sure that internally they're not actually stored on the heap and referenced using, well, references? – Sergiu Dumitriu Jan 05 '13 at 09:28
  • It doesn't make sense to talk about how data is represented internally in Javascript... you may discuss how data is represented internally in V8 or SpiderMonkey but that is irrelevant to this question. I was just saying that it's pointless to make a distinction between native types and objects for copy/passing because they behave exactly the same. Of course they are different for some other reasons (with differences being visible at Javascript level), but not for the copy/pass part. – 6502 Jan 05 '13 at 10:16