31

Please read the comments in the code below to know what I am trying to ask.

Expected Output: As per pass-by-reference mechanism in JavaScript, objOne is expected to log {} at the end, because objTwo was initialized with {}.

var objOne = {
  x: 1,
  y: 2
};

var objTwo = objOne;

// change the x vlaue to 2 by objTwo
objTwo.x = 2;

// Change the value of key x in objOne as well - pass by reference mechanism
console.log(objOne); // { x: 2, y: 2 }

/*** Pass by reference is understood in code, above this comment ***/

// Now what if objTwo initialized with empty object
objTwo = {};

console.log(objOne); // { x: 2, y: 2 } but expected output = {}

// As per pass by reference mechanism. objOne is expected to log {}, because objTwo was initialized with {}.
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • 5
    In case 1 both `objOne` and `objTwo` refer to the same object. So so can change `x` through any of them. Reinitializing `objTwo` means you make it no longer refer to the same object. This does not cause all other existing references to become {} – Thiyagu May 18 '16 at 05:14
  • 2
    It's the *object* that is by-reference, not the variable. – Bergi May 18 '16 at 05:15
  • See this: http://stackoverflow.com/questions/13506398/why-are-objects-values-captured-inside-function-calls/13508654#13508654 – slebetman May 18 '16 at 05:15
  • 1
    When you do objTwo = {}; what happens is that the reference i changed to an empty object. – Manish May 18 '16 at 05:15
  • 4
    JavaScript doesn't have "pass by reference" at all, **period**. JavaScript is a purely pass-by-value language. Pass by reference has a specific meaning in computer programming: It's passing a reference to a **variable** into a function. JavaScript never does that. – T.J. Crowder May 18 '16 at 07:05
  • *"Change the value of key x in objOne as well - pass by reference mechanism"* No, not at all. It's an "object reference" mechanism, not pass-by-reference. – T.J. Crowder May 18 '16 at 07:09
  • @T.J.Crowder I wish there was a better universal term for object references / object pointers, as this is an extremely common confusion! – IMSoP May 18 '16 at 14:12

9 Answers9

53

When you assign one variable to another, it's not that both those variables are now linked by reference; you're misunderstanding what "pass by reference" means here.

A variable holding an object does not "directly" hold an object. What it holds is a reference to an object. When you assign that reference from one variable to another, you're making a copy of that reference. Now both variables hold a reference to an object. Modifying the object through that reference changes it for both variables holding a reference to that object.

When you assign a new value to one of the variables, you're just modifying the value that variable holds. The variable now ceases to hold a reference to the object, and instead holds something else. The other variable still holds its reference to the original object, the assignment didn't influence it at all.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • 25
    *"you're misunderstanding what "pass by reference" means here"* I'd take the opportunity to tell them that JavaScript doesn't have pass by reference **at all**. – T.J. Crowder May 18 '16 at 07:06
  • "you're just modifying the value that variable holds" I think this would be more precisely worded if it said, "you're just modifying the *reference* that variable holds". – jpmc26 May 18 '16 at 09:31
  • 2
    @jpmc26 No. If you assign something other than an object, there will be no "reference" anymore. The value the variable holds is a reference, but the variable can also hold other values. – deceze May 18 '16 at 09:34
  • Oh, I see what you mean. Apologies. I think I got confused because the OP's question doesn't refer to that situation. It only assigns a new object to a variable, so I read, "assign a new value," as the, "assign a new object," operation the OP performs. – jpmc26 May 18 '16 at 09:38
  • @T.J.Crowder but it does have "pass by *value of object reference*" – Caleth May 18 '16 at 12:25
  • 5
    @Caleth: It's purely pass-by-value. Yes, the value can be an object reference. Object references are just values like any other. – T.J. Crowder May 18 '16 at 12:41
  • 2
    yes, and use of that value gives you reference semantics on the Object, which is what people care about when they say "pass by reference" – Caleth May 18 '16 at 12:44
  • 2
    @Caleth: (If you don't `@` someone who isn't the author, they won't get notification of your comment.) That isn't what pass-by-reference means, so if you run into those people, explain it to them. :-) Pass-by-reference is a *term of art* in the computer science world. It refers to passing a reference to a **variable** into a function. JavaScript doesn't do that. One of the most powerful things to understand about object references in langauges like JavaScript is that *they're just values*. – T.J. Crowder May 18 '16 at 14:09
  • @deceze Correct me if I'm wrong, but since *everything* in JS is an object, surely the "value" and "object reference" really are equivalent in this case. The only reason things like strings behave a bit differently is that they're implemented as immutable - they only have methods that return a new object, no mutators - but passing and assignment are technically using the same thing. – IMSoP May 18 '16 at 14:09
  • @IMSoP: Everything in JavaScript isn't an object (numbers, primitive strings [as opposed to String objects, JavaScript has both], undefined, and booleans are all *primitives*, not object types). So no, *value* and *object reference* are not equivalent terms. Now, there's a point of view in the OOP world (not a common one, but a valid one) that you could consider all primitives to actually be instances of immutable types, but that's not something either the specification or implementations take on board (except implementations probably do for primitive strings). – T.J. Crowder May 18 '16 at 14:11
  • @T.J.Crowder I know what the definition is, I am saying that in the land where everything is an object, "pass by value of object reference" is equivalent to "pass by reference". You need a distinction only when you can have "pass by reference to object reference" etc – Caleth May 18 '16 at 14:13
  • 2
    @Caleth: No, not at all. Again: Pass-by-reference means passing a reference to a **variable**, such that if you pass that variable (by reference) into a function, the function can change **the variable**. JavaScript doesn't have that. C++ does with `&` arguments, and C# does with its `ref` and `out` keywords, but JavaScript (like Java) doens't. Pass-by-reference example (in C#): `void foo(ref arg) { arg = 2; } int x = 1; foo(ref x); Console.WriteLine(x);` shows 2, because `foo` changed `x`. – T.J. Crowder May 18 '16 at 14:15
  • 1
    @T.J.Crowder I stand corrected. I was misled by the fact that `'foo'.length` works, but apparently that's just a very invisible form of autoboxing. I shall have to learn quite what difference that makes some time... – IMSoP May 18 '16 at 14:16
  • @IMSoP: Yeah, the autoboxing of strings and numbers is...well...let's call it a *special* part of the language definition. :-) – T.J. Crowder May 18 '16 at 14:16
  • @Caleth [This example (in PHP)](http://stackoverflow.com/a/19847845/157957) shows the difference between "pass by reference" and "pass by value of object reference" in a language that has both. Just because JS only has one of them doesn't mean that the two become equivalent. – IMSoP May 18 '16 at 14:21
  • @T.J.Crowder I think we are saying the same things - in your previous comment to me if you replace all the instances of variable with object you arrive at my point. I agree in the strict definition there is a difference, but Java(script) is such that there is no behavioral difference – Caleth May 18 '16 at 14:21
  • @IMSoP I am aware of the difference, my point is that in a language where there only is "pass by value", a value of type "object reference" gives you exactly the sames things as a language with no objects and a choice between "pass by value" and "pass by reference" – Caleth May 18 '16 at 14:25
  • @Caleth: No, we're not saying remotely the same thing. Pass-by-reference is a [*term of art*](http://www.merriam-webster.com/dictionary/term+of+art). It is specific to passing references to variables so functions can change their values. You can't replace "variable" in my comments because then you're not talking about pass-by-reference anymore. The "reference" in pass-by-reference and the "reference" in "object reference" have nothing, whatsoever, at all, to do with one another. They're different things, that are *used* for different things, and conflating the two is just a road to confusion. – T.J. Crowder May 18 '16 at 14:32
  • @Caleth Have a look at the example, and you'll see that it *doesn't* give you the same things - you cannot write a function which behaves the same way as the last one in that example in JS. Also note that the example I gave is in PHP, which is absolutely not "a language without objects". – IMSoP May 18 '16 at 14:42
  • @IMSoP It is *because* you cannot write such a function in JS that I am saying that *in the case of javascript* you gain "referenceness" entirely analogous to call by reference through "value of object reference". In languages with *both*, there are behavioral distinctions to be drawn, generally due to the presence of "reference to object reference" etc – Caleth May 18 '16 at 15:01
  • @IMSoP When I say "language without objects" I am talking something like Haskell, in that Haskell programs tend to think of everything as values of some type, and identity doesn't come into it. Not that Haskell has pass by reference either, so it isn't applicable to my above point either – Caleth May 18 '16 at 15:05
  • @Caleth But the behaviour is not "exactly analagous". It's like saying that if you can't swim, swimming and walking are the same thing - whether you can do them both or not, they are still different things; you wouldn't say "in the case of someone who can't swim, swimming means walking". I can still describe what pass by reference *would* do, if JS had it, but it simply doesn't. I can also imagine what PHP would be like if it *didn't* have it, and object passing wouldn't magically become more powerful to compensate, just as you don't gain the ability to walk underwater if you can't swim. – IMSoP May 18 '16 at 15:52
  • @Caleth And no, it has nothing to do with "reference to object reference" or anything so complex. As [this article (about Java)](http://javadude.com/articles/passbyvalue.htm) puts it: if you can write a "swap" function, which swaps the values of two values (of whatever type you happen to be interested in) in your language, it has pass-by-reference. You cannot write that function in JS, regardless of what kinds of object you use, so it doesn't have pass-by-reference. – IMSoP May 18 '16 at 15:58
  • I can't pass a variable by reference in javascript. What I can do is *start with a value in a box*, pass a reference to the box, and carry on using the *value in the box* - rather than `val = 1; doStuff(val); alert(val)` you have `obj = { val: 1 }; doStuffViaValObject(obj); alert(obj.val);` – Caleth May 18 '16 at 16:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/112312/discussion-between-caleth-and-imsop). – Caleth May 18 '16 at 16:03
14

When you evaluate

objTwo = {};

Javascript interprets that as reassigning objTwo to a new literal empty object, and leaves its old value alone.

If you want to remove a key from objOne by reference, you can use the delete keyword:

delete objTwo.x;  // also deletes the x property of objOne
Razzi Abuissa
  • 3,337
  • 2
  • 28
  • 29
7

When 2 variables are pointing to same object, it doesn't mean that they're now magically 'tied' to each other.

In your case, objTwo = {} is simply changing objTwo to point at the new object you created.

haim770
  • 48,394
  • 7
  • 105
  • 133
5

objTwo = {}; doesn't work the way you think it works. I usually recommend thinking of variables as "pointers".

objOne and objTwo are two totally different variables. When you did objTwo = {};, what it did was have the objTwo variable point to another object. It does not alter the objOne variable.

Let's visualize:

var objOne = {
  x: 1,
  y: 2
};

// objOne -> { x: 1, y: 2 }

var objTwo = objOne;

// objOne -> { x: 1, y: 2 } <- objTwo

objTwo.x = 2;

// objOne -> { x: 2, y: 2 } <- objTwo (update object via objTwo variable)

objTwo = {};

// objOne -> { x: 2, y: 2 }, objTwo -> {}
Joseph
  • 117,725
  • 30
  • 181
  • 234
4

I agree with accepted answer, this is just some code to back it up.

let objOne = {x: 1, y: 2};
let objTwo = objOne; // referencing to same thing

objTwo.x = 2;
console.log(objOne, objTwo); // output {x:2, y:2}, {x:2, y:2}

let objThree = {};
objTwo = objThree; // notice this. Same as "objTwo = {}", except now you have objThree as initial reference
console.log(objOne, objTwo, objThree); // output {x:2, y:2}, {}, {}

You can easily notice what happened by changing objTwo reference or adding it complete new value as it was shown in question example.

1

JavaScript pass by reference is different, your object is treated as a reference as long as you're changing its attributes like obj.x = 1, but assignment of the object variable itself (obj = []) will treat it as value-based variable.

Shadi Shaaban
  • 1,670
  • 1
  • 10
  • 17
1

only delete can call initialize state ..

for(var i in objOne){
    delete objOne[i];
}

@nrabinowitz saying

  • Javascript is always pass by value, but when a variable refers to an object (including arrays), the "value" is a reference to the object.
  • Changing the value of a variable never changes the underlying primitive or object, it just points the variable to a new primitive or object.
  • However, changing a property of an object referenced by a variable does change the underlying object.
Jack jdeoel
  • 4,554
  • 5
  • 26
  • 52
1

As per pass-by-reference mechanism in JavaScript

Let's get this out of the way: there is no pass-by-reference mechanism in JavaScript. Pass-by-reference is a very specific feature. To know whether a language supports it, you should check whether it is possible to pass a variable with an immutable value to a function (for instance an integer), and after that call see that this variable has a different immutable value. If this is not possible, then the language does not support pass-by-reference. JavaScript does not support it. C does not support it. C++ does support it (by declaring a function parameter with &).

As to your code example; let's visualise it.

First phase

After the first two var statements we get this:

objOne
  ↓  
┌───────────┐
│ x: 1      │
│ y: 2      │
└───────────┘
  ↑  
objTwo

Only one object was created (using object literal syntax).

After objTwo.x = 2, we get:

objOne
  ↓  
┌───────────┐
│ x: 2      │
│ y: 2      │
└───────────┘
  ↑  
objTwo

Only one property value was changed, in the only object that was created. Whether you look at the object via variable objOne or objTwo does not make a difference.

Second phase

objTwo = {} creates a second object and assigns its reference to objTwo. Now we have two, distinct objects:

objOne
  ↓  
┌───────────┐
│ x: 2      │
│ y: 2      │
└───────────┘

objTwo
  ↓  
┌───────────┐
└───────────┘

You cannot change which object objOne is referencing without making an assignment to objOne. Even though objOne and objTwo first referenced the same object, these variables are still distinct references. In the first phase we saw we can mutate the object that objOne references, but it is still the same object -- just one that was subject to some mutation. It is not possible to make objOne reference another object by making an assignment to objTwo. You really need to assign to objOne to make that happen.

Conclusion

There is no pass-by-reference mechanism in JavaScript. In JavaScript objects are accessed and manipulated through references. objTwo is not an alias for objOne, it only is a duplicate reference for the same object. As soon as another reference is assigned to objTwo, we have two distinct references.

trincot
  • 317,000
  • 35
  • 244
  • 286
0

This is how pass-by-reference works. Here objTwo is referring to objOne so whatever you do with objTwo will also happen with objOne.

Uddesh Jain
  • 1,064
  • 2
  • 15
  • 16