There's a small test. I expect both obj\d object have their a menmber changed in the end. However the change1 style doesn't work, I wonder why, or why not, should it behave like this?
<button id="btn1" onclick="test()">Change</button>
<script>
var obj1 = { a : {strblahblah: "blah"} };
var obj2 = { a : {strblahblah: "blah"} };
function test(){
change1(obj1.a);
change2(obj2);
alert("obj1: " + obj1.toSource() + "\r\nobj2: " + obj2.toSource());
}
function change1(obj){
obj = {str: "change1"};
}
function change2(obj){
obj.a = {str: "change2"};
}
</script>
Result(after you click the button):
obj1: ({a:{strblahblah:"blah"}})
obj2: ({a:{str:"change2"}})
What's happening in change1 is that obj initially holds a reference to the object in obj1.a. However, the line:
obj = {str: "change1"};
doesn't change obj1.a. Instead it creates a new object ({str: "change1"}) and changes obj so that it now points to this object instead of obj1.a.
In contrast, change2 has obj initially holding a reference to the object in obj2, and has the line:
obj.a = {str: "change2"};
which accesses the internal structure of the referenced object (i.e. obj2) and hence makes actual changes to that object.
When you pass obj1.a to change1(), you are sending the value of obj1.a which itself is another object. But when you send the obj2 to change2(), its taking the reference of the object, and when you assigned the value the original value got changes, where as in the first case this had not happened.
As thg437 suggested, this best explains the case,
Is JavaScript a pass-by-reference or pass-by-value language?
From MDN:
The parameters of a function call are the function's arguments.
Arguments are passed to functions by value. If the function changes
the value of an argument, this change is not reflected globally or in
the calling function. However, object references are values, too, and
they are special: if the function changes the referred object's
properties, that change is visible outside the function
In change1 you are passing obj.a, which is actually a value (because it is an object reference, not the object itself). This means that you receive a copy of that reference in change1 and then modify it to point to a new object. All you've done is modify the copy of the reference that was passed into the function so that it's effectively pointing to something else in memory.
In change2 you are passing obj which is an object reference as well, but you are then modifying the a property of that reference, so you're getting the object that's pointed to by the reference and modifying its a property. This object that is modified is the same one that is pointed to by both the copy of the object reference you received by value in the function and the reference obj1 at the top of the code.
This statement obj = {str: "change1"};
causing obj to refer to something other than the passed argument,
where as obj.a = {str: "change2"};
causing "a" property in passed argument to be changed to something else.
It is expected, in 1st case you're just changing reference of input and in other case you're actually modifying input parameter.
Related
This question already has answers here:
Is JavaScript a pass-by-reference or pass-by-value language?
(33 answers)
Closed 2 years ago.
I don't know why in the following example it is not possible to define null to the object, however it is possible to add properties to it
function callByReference(myFunc) {
myFunc.b = 2;
myFunc = null; // this not set null to Object arg
// myFunc.b = 2; //If I set it after, throws error
}
let customObj = {
a: 1
};
console.log("Before call by reference method");
console.log(customObj);
callByReference(customObj);
console.log("After call by reference method");
console.log(customObj);
Even if I set it null first and then adding a property throws an error;
I don't understand this behavior well. Is there any reason? maybe I'm not understanding how javascript works when passing by reference a argument
The way Javascript works, every variable name is essentially a pointer (or reference) to some value. When you create a new variable by referencing an old object, or when you call a function, you're basically copying the pointer. Eg:
const fn = (param) => {
// ...
};
const obj = {};
const obj2 = obj;
fn(obj);
Above, obj2 and param both point to the empty object that was initially created in obj, you might think of it as:
obj: MemAddress1234
obj2: MemAddress1234
param: MemAddress1234
Whenever you use the = assignment operator, you reassign the binding for that variable name, but doing so doesn't affect any other variables that may have pointed at the same thing:
param = null;
results in something like
obj: MemAddress1234
obj2: MemAddress1234
param: MemAddress0
At least, that's one way to look at it. The link between obj and the empty object, and the link between obj2 and the empty object, remain unaffected, because it's only the param variable name was reassigned.
Reassigning a variable by itself will almost never have any side-effects on anything else. The two exceptions are with arguments in sloppy mode:
function foo(a, b) {
console.log(arguments);
a = 5;
console.log(arguments);
}
foo(1, 2);
and with mutable variables exported by ES6 modules.
This is the way the JavaScript works:
Parameter is always pass by value, but when a variable refers to an object, 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 (but if you change a property a property in underlying object is changed too).
First, you created a customObj object, that is stored somewhere in the memory.
Then you have a function with an argument function callByReference(myFunc).
If you call the function with your object callByReference(customObj) it will assign a reference pointing at customObj to the myFunc. So now myFunc points to the same place in memory as customObj.
Now, if you modify something inside myFunc, you are changing the same memory as customObj - that is why myFunc.b = 2; will modify customObj. But if you assign something new to the myFunc, you are modifying where it is pointing, not what is inside. So myFunc = null; is like telling "now myFunc points to null memory", but customObj is still pointing to the same part of the memory, so the data is the same.
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?
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!"
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.
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.
When a variable refers to an object the value is a reference to the object (Referred from: Javascript by reference vs. by value )
function fun1(obj) {
obj.first = 1; //it affects the object ->obj
}
var myObj1 = {first: 0};
fun1(myObj1); //sending the object to the function
console.log(myObj1.first); // 1
But I would like to change the variable from an object, for example
function fun2(obj) {
obj = 1; }
var myObj2 = {first: 0};
fun2(myObj2.first);
console.log(myObj2.first);
Is there any way to achieve this?
Is there any way to achieve this?
Not directly. All you can do is pass an object and have the function modify a property on it, as in your first example. JavaScript does not have pass-by-reference, just pass-by-value. (The value may be an object reference, of course, but it's still a value.) There's no way in JavaScript to directly modify the variable/property you're passing into the function, because what the function receives is a copy of the value of that variable/property, not a reference to that variable/property.
Just to be clear about something: In your first code block, you said you were "sending the object to the function." That's incorrect. You send a reference to the object to the function.
This is the key thing to understand: Variables, properties, and function arguments (collectively, "variables") contain values, and those values are copied when you use assignment or when you pass them into functions. The value that refers to an object is called an object reference, because the value isn't the object, it's a reference to (pointer to) the object elsewhere in memory. The reference is copied when you pass it into a function, the object is not.
Don't confuse the "reference" in "object reference" with the "reference" in "pass-by-reference," they're completely different things. (In pass-by-reference, the reference is to the variable, not an object. JavaScript doesn't have pass-by-reference.)
I'm reading that in JavaScript, a common point of confusion arises because variables of primitives are passed by value, and variables of objects are passed by reference, while in function arguments, both primitives and references are passed by value.
In the course of my tinkering, I've made up the following code, but am having trouble wrapping my head around it.
> function setName2(obj) {
... obj.name="matt";
... obj = new Object();
... obj.name="obama";
... }
If I set
var person = new Object();
person.name = "michelle";
Then run
> setName2(person);
I get
> person.name;
'matt'
Which makes sense because the new object created is a pointer to a local object, hence not affecting the property of the global 'person'.
However, what if I first set
var obj = new Object();
obj.name = "michelle";
Then run
> setName2(obj);
?
I get the same outcome. Does this mean that the compiler recognizes the two variables of the same name (obj global and obj local) as references to different locations within the heap, each having some different pointer association, or is there a different explanation for this phenomenon?
JavaScript does not have pass-by-reference; everything is passed by value. However, some values are themselves references to objects. This distinction (pass-by-reference vs. is-a-reference) leads to much confusion.
An example to clear things up:
function f(o) { ... }
var obj = { foo: 42 };
f(obj);
No matter what you do in f, obj will always refer to the same object because the argument is not passed by reference. However the value obj, which is copied into o, is itself a reference to an object. This is why any property changes made to o inside the function will be visible on obj after it returns.
while in function arguments, both primitives and references are passed by value.
This is not true. There is nothing special about function arguments.
function setName2(obj) {
This accepts a reference to an object as an argument.
obj.name="matt";
This modifies the name property of the object that reference points to.
obj = new Object();
This replaces the reference to the original object with a reference to a new object.
obj.name="obama";
This modifies the name property of the new object. The original object is unchanged.
The confusion comes from the fact that "passed by reference" is misinterpreted by people or used in a wrong sense.
Parameters are passed by value. This means that changing the value inside the method doesn't change the original value.
In case of primitives, the value of a primitive is its value.
In case of objects, the value of an object is a reference to it. You can access and change object's content but you can't change the value of the reference itself.
In other programming languages, like C++ or C#, "passing by reference" means that you pass:
- a reference to a primitive type
- a reference to a reference to an object
In such case, not only the content of an object can be changed but also a reference itself can be changed.
There is NO passing by reference in Javascript.
Javascript uses pass-by-value.
The confusion is that objects are hold by reference variables (kind of pointers). In fact most common languages (java, javascript, etc.) do not have a real pass-by-reference behaviour. Another way to understand this could be pass-reference-by-value, although, formally, there is not such a thing.
That means when you pass an object as a parameter, you are actually passing a reference to the object by-value.
function setName2(obj) {
...
}
setName2(person);
here the contents of person (a reference, or "pointer" if you like) is copied by-value to a new local variable: obj.
obj and person are different variables that hold a reference to the same object.
So, doing obj = new Object(); makes obj to point to the new object. But person is unaffected since it is still a completely different variable.
I don't know where you read that, but it's absolutely not true. Objects are passed by reference, full stop. Whether or not it's a function parameter is completely irrelevant.
I'm sure I'm missing something obvious here, but I'd expect the argument to the changeMe method to be passed "by reference" - in other words, that changes to the parameter inside the function will change the variable outside the function.
The following was run in jsfiddle, using Chrome's F12 developer tools to show the console output. http://jsfiddle.net/fzEpa/
var object1 = { Property1: 'Value1' };
changeMe(object1);
console.log(object1);
function changeMe(refToObject) {
console.log(refToObject);
refToObject = { Property1: 'Value2' };
console.log(refToObject);
}
It is passed by reference, but it is a reference to the object, not to the object1 variable (which is also a reference to the object).
You are overwriting the reference to the object with a reference to a new object.
This leaves the original reference to the original object intact.
To modify the object, you would do something like this:
function changeMe(refToObject) {
refToObject.Property1 = 'Value2';
}
A reference to the object is passed as the argument value. However:
refToObject = { Property1: 'Value2' };
At this point you lose the reference to the object formerly referenced by refToObject as you're assigning this variable to reference a different object.
Now if you were to edit the refToObject's properties instead of discarding the former object reference, your code would work as exepected (as firstly explained in #Quentin's answer).
If you're familiar with C++ this would be equal to doing something like this:
void f(int* ref) {
ref = new int(3);
}
int* a = new int(5);
f(a);
printf("%d",a); //Prints 5
you are trying to redefine the Property 1,so it wouldnt work. in order to work with pass by reference ypu have to do it this way refToObject.Property1='Value2' inside your ChangeMe() function . refer this for better understanding Pass Variables by Reference in Javascript