0

I studied that Javascript passes objects by 'pass by reference' to functions. When those objects are mutated/updated inside a function, then it affects the original object. This is clear!

But, what if we replace the passed object1 with another object2(also passed as a parameter) inside that function? Why is it not updating the original object?

Here is the code snippet,

var num = 10,
    name = "Addy Osmani",
    obj1 = {
      value: "first value"
    },
    obj2 = {
     value: "second value"
    },
    obj3 = obj2;
 
function change(num, name, obj1, obj2) {
    num = num * 10;
    name = "Paul Irish";
    obj1 = obj2;
    obj2.value = "new value";
}
 
change(num, name, obj1, obj2);
 
console.log(num); // 10
console.log(name);// "Addy Osmani"
console.log(obj1.value);//"first value"
console.log(obj2.value);//"new value"
console.log(obj3.value);//"new value" 

Here if you see, I passed two objects, ob1 and obj2 to function. They are passed as reference.

Due to this line "obj3=obj2", 'obj3' refer to the same reference of 'obj2' and any changes made to 'obj2' updates 'obj3' and it's clear.

My confusion is, in change() I replaced 'obj1' with 'obj2' (obj1=obj2). Here is 'obj1'referencing the same location of 'obj2'? If yes, then why updating obj2.value is not effecting obj1.value?

sridhar
  • 11
  • 4
    *I studied that Javascript passes objects by 'pass by reference' to functions.* That's incorrect and a common misconception. Everything is passed by value in JavaScript, period. It's just that when a primitive is passed you get a copy of the primitive and when an object is passed you get a copy of the memory location of the object. – Scott Marcus Feb 24 '18 at 01:38
  • Yes. I do know that. As objects are passed by reference, then why replacing obj1 with obj2 ( obj1 = obj2;) in change() and updating obj2.value is not effecting obj1.value. obj1 and obj2 are not referencing to the same memory location? – sridhar Feb 24 '18 at 01:43
  • Uh, no. As I've just said, objects are passed by value, not reference. Everything is passed by value. – Scott Marcus Feb 24 '18 at 01:45
  • Javascript has 5 data types that are passed by value: Boolean , null , undefined , String , and Number . We'll call these primitive types. Javascript has 3 data types that are passed by reference: Array , Function , and Object. [Explaining Value vs. Reference in Javascript](https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0) – Ele Feb 24 '18 at 01:53
  • 1
    Possible duplicate of [Pass-by-reference JavaScript objects](https://stackoverflow.com/questions/37290747/pass-by-reference-javascript-objects) – Ele Feb 24 '18 at 01:53
  • 3
    @sridhar Objects are not passed *by* reference. They're passed *as* references. The object *reference value* is passed around - by value. Parameters and variables never are references to other variables - they might however hold a value that references an object. – Bergi Feb 24 '18 at 01:53
  • 2
    @Ele That is incorrect. Everything is passed by value in JavaScript, it's just that objects are passing a reference to a memory location and not the object itself. It's a common point of confusion and that link you posted falls under that heading. – Scott Marcus Feb 24 '18 at 02:07
  • @Ele In fact, in the comments, the author of the article states (after having been called out for inaccuracies in the article) ***I know my article isn’t technically correct in most ways. I simply attempted to provide a simple explanation to help people understand the behavior they see.*** – Scott Marcus Feb 24 '18 at 02:11
  • [Primitive Data Types are passed By Value and Objects are passed By Reference.](https://hackernoon.com/grasp-by-value-and-by-reference-in-javascript-7ed75efa1293) – Ele Feb 24 '18 at 02:12
  • 3
    @Ele As I've said, this is a very common point of confusion with people. But the fact is that everything is passed by value. Post all the links you want. I can post some links to sites that claim the earth is flat. Doesn't make it true. – Scott Marcus Feb 24 '18 at 02:14
  • @ScottMarcus your comment is confusing even more, further when you say "period!". The OP needs to read more about what's the real differences between primitive params and objects as param. – Ele Feb 24 '18 at 02:15
  • @Ele Yes, it can be confusing and that's why so many people misunderstand this issue and yes, the OP does need to learn more about the differences, but passing incorrect information to him isn't going to help. – Scott Marcus Feb 24 '18 at 02:18
  • @ScottMarcus ok, have a good day! – Ele Feb 24 '18 at 02:20
  • @Ele Here is (what I believe) is the applicable section of the [ECMA specification](http://www.ecma-international.org/ecma-262/6.0/#sec-getvalue) on handling arguments. – Scott Marcus Feb 24 '18 at 02:20
  • @ScottMarcus Actually [the spec doesn't really help here at all](https://stackoverflow.com/q/23554770/1048572) – Bergi Feb 24 '18 at 02:22
  • @Bergi Did you look at the ECMA link I posted? It seems to state that with a primitive passed as an argument, return the value and with an object return the Environmental Record. – Scott Marcus Feb 24 '18 at 03:05
  • @ScottMarcus No, `getValue` has nothing to do with primitive vs object values. All it does is evaluate property and identifier references in expressions. – Bergi Feb 24 '18 at 03:30
  • @sridhar I have updated my answer to be more clear. – Scott Marcus Feb 24 '18 at 16:41

3 Answers3

2

This has nothing to do with how your references are passed. It has to do with scope and the fact that your function argument names are the same as your higher scoped variable names.

If yes, then why updating obj2.value is not effecting obj1.value?

It is affecting obj1.value, but only from within the function because you only made the change to the local obj1 variable.

The issue is simply that you have local function argument names that hide duplicate names from the global scope. Any changes you make in your function are referring to newly created local variables and don't affect the global ones. Since you never actually make any changes to the object that obj1 originally pointed to, from within your function, you will never see any changes outside of it either.


Let's walk through this....

Inside your function, obj1 is a new local variable that does start out being a copy of what's in the Global obj1 variable and now there are two obj1 variables that point to the same one actual Global object. But, then you change what the local obj1 variable points to with this:

obj1 = obj2;

So now, there are 3 ways to access the Global obj2 object:

  • the Global obj2 variable (window.obj2)
  • the local obj1 variable (obj1)
  • the local obj2 variable (obj2)

You then make a change to the object that those 3 references point to with:

obj2.value = "new value";

At this point, you have done nothing but modify the object referenced by these 3 variables (the Global obj2 object). The Global obj1 object has not been altered in any way.

So, inside the function, when you access obj1, you are getting a reference to the Global obj2, but when the function returns, all local variables are destroyed and you now go back to having just one way to access each of the two objects in memory. Since you never actually modified the Global object that obj1 points to, you see no change there, but you did modify the object that Global obj2 points to from within the function, so you do see that object modified.

If you had actually modified the Global object that obj1 originally referenced from within the function, you would have seen those changes persist outside of it.

See comments inline:

var num = 10,
    name = "Addy Osmani",
    obj1 = {
      value: "first value"
    },
    obj2 = {
     value: "second value"
    },
    obj3 = obj2;
 
function change(num, name, obj1, obj2) {
    // All your arguments have the same names as global variables
    // Changes to primitives here won't affect the primitives outside
    // of the function because copies of those primitives were passed
    // into the function and your local variables hold those copies:
    num = num * 10;
    name = "Paul Irish";

    // Let's do the simplest test possible with your object references...
    // Just use the local variables to see if they affect the Globals
    obj1.value = "Changed from within the function!";
    obj2.value = "Me too!";
}
 
change(num, name, obj1, obj2);
 
console.log(num);         // 10 (the global num)
console.log(name);        // "Addy Osmani" (the global name)
console.log(obj1.value);  // "Changed from within the function!"
console.log(obj2.value);  // "Me too!"
console.log(obj3.value);  // "Me too!"
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • Just want to be clear that, if you see in change() I am doing `obj1 = obj2a;' So any updates done to `obj2' will also obj1' or not which is in global? This is my confusion – sridhar Feb 24 '18 at 02:01
  • @sridhar See my updated answer for a more detailed explanation. – Scott Marcus Feb 24 '18 at 16:50
0

I studied that Javascript passes objects by 'pass by reference' to functions.

First of all, JavaScript has pass-by-value only, just like Java. Second, "objects" cannot be "passed" in JavaScript because "objects" are not values -- the only values are primitives and references (pointers to objects). All objects are manipulated through references.

When those objects are mutated/updated inside a function, then it affects the original object. This is clear!

Passing is by value, so it's the same as assignment of the passed value to the parameter variable inside the function. When you assign one reference to another, you get two references that point to the same object. Modifications to this one object through one reference can be seen through another reference to the same object.

But, what if we replace the passed object1 with another object2(also passed as a parameter) inside that function? Why is it not updating the original object?

As mentioned above, "objects" are not values in JavaScript. What is passed and what is held in a variable is a reference, i.e. a pointer to an object. The parameters obj1 and obj2 hold references (because references were passed in). When you do obj1 = obj2;, both obj1 and obj2 now hold the reference that was in obj2, i.e. now they both point to the object that obj2 used to point to, and now modifications through the references in either variable obj1 or obj2 will modify that same object. The object that obj1 used to point to is unaffected -- it's just that there is no variable in the function that points to it anymore.

newacct
  • 119,665
  • 29
  • 163
  • 224
-1

All objects are internally memory references, when you do var1 = var2, var1 now points to var2 and not the other way around (var2 pointing to var1). The problem in your understanding is that the right side is assigned to the left side, not the left side to the right side.

Jiby Jose
  • 3,745
  • 4
  • 24
  • 32
  • oh no!! I got it right, you misunderstood me! As you said in example, when we do `var1=var2`, `var1` refers to `var2`. So any change we do to `var2` should update `var1` right? But this is not happening when I do it in function when passed as parameters! – sridhar Feb 24 '18 at 01:54
  • @sridhar well, you didn't read it clearly, lets go through this okay, you have `var1` lets say its an object at `mem1` location, it is passed into a function as say `var2` which also points to `mem1`. Now you assigned `var3` an object at `mem2` to `var2`, now `var2` points to `mem2`. So to put it back `var1` points to `mem1` `var2` points to `mem2` `var3` points to `mem2` if you change values on `var2` or `var3` they both are updated, but it wont update `var1`, it is just another memory location – Jiby Jose Feb 24 '18 at 10:04