If in javascript object properties are passed by reference why this doesnt work:
var myObj={a:1}
function myFun(x){
x=2;
}
myFun(myObj.a);
// value myObj.a is still 1
but on the other hand if you do this:
var myObj={a:1}
function myFun(x){
x.a=2;
}
myFun(myObj);
// this works myObj.a is 2
Primitive values are passed by value. Objects are passed by reference.
Object properties are passed by based on their data type.
Here you are passing an integer - x represents the value 1. Assigning x the value 2 does not reference the original object.
Let's say the property you pass in is an array. And the 2nd function I call receives an array and you make changes to that array. Then the changes will persist to the object because the object's property contains a reference to the array you modified. You didn't technically modify the object at all... you just modified the array which is referenced in the object. When you pass an object property to a function, it's not aware that it belongs to an object at all.
See example, similar to yours:
var myObj={a:[1]}
function fn1(x){
x=2; //Overwrites x in this scope to the new primitive 2.
//This isn't reflected in myObj because x is not a
//reference to myObj.a it is a reference to the array
//that myObj.a contains (the [1]).
}
function fn2(x){
x.push(2);
}
fn1(myObj.a); //myObj.a is [1]
fn2(myObj.a); //myObj.a is [1,2]
your first example doesn't work, because object properties are not passed by reference (unless the property itself also is an object).
objects, as you noticed, are passed by reference - thats the reason your second example works.
When you pass a base data type, it is passed by value. That is for integers, you pass the parameter by value so a copy of it is made in the local scope. Objects however are passed by reference so the function has access to the variable. You could pass it by reference, but its easier to do
Obj.a=fun(Obj.a);
Related
Why does JavaScript treat the scope of an array differently than it does the scope of other variables? Typically, if one passes a variable in a global scope into a function as a parameter, it is then local and changing it within the function does not change the value of the global variable. For example:
var globalInt = 1;
function test1(x){
x = x + 1
}
test1(globalInt);
console.log(globalInt); //globalInt is still 1
However, it appears the same does not apply when passing an array of values.
var globalArray = ["TEST"];
function test(x){
x[0] = x[0].toLowerCase()
}
test(globalArray);
//globalArray is now ["test"] instead of ["TEST"]
console.log(globalArray[0]);
This happens for me when I test in Chrome, but I have not tested it in other browsers so far. Why does this happen and does it happen in other browsers?
This is simply because an array (which is an Object) are passed by reference while primitives are not. Note that technically it is passed by value but in this case that value is a reference, thanks Esteban
A object is automatically passed by reference, without the need to specifically state it
If you pass an object (i.e. a non-primitive value, such as Array or a user-defined object) as a parameter and the function changes the object's properties, that change is visible outside the function, as shown in the following example:
MDN Link
Yes... JavaScript objects and arrays (which are objects) are passed by reference. But you should remember to read the method signature explicitly because some array methods don't alter the original array but return a new one. Read the MDN documentation carefully about the method in question. Array.prototype.map() would actually leave the original array intact and return a brand new array which you'd need to set to assign to a variable.
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.
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.
Consider the following code
function add(x, y) {
alert(arguments.length);
var total = x + y;
return total;
}
add(); // NaN alerts 0
add(2,3); // 5 alerts 2
add(3,3,5); //6 alerts 3
Where is arguments defined? How come it is available inside my add function?
It is automatically created for all functions.
See https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Functions_and_function_scope/arguments
A detailed explanation about when and how the arguments object is created:
From the ECMAScript specification:
10.1.8 Arguments Object
When control enters an execution context for function code, an arguments object is created and
initialised as follows:
The value of the internal [[Prototype]] property of the arguments object is the original Object prototype object, the one that is the initial value of Object.prototype (see 15.2.3.1).
A property is created with name callee and property attributes { DontEnum }. The initial value of this property is the Function object being executed. This allows anonymous functions to be recursive.
A property is created with name length and property attributes { DontEnum }. The initial value of this property is the number of actual parameter values supplied by the caller.
For each non-negative integer, arg, less than the value of the length property, a property is created with name ToString(arg) and property attributes { DontEnum }. The initial value of this property is the value of the corresponding actual parameter supplied by the caller. The first actual parameter value corresponds to arg = 0, the second to arg = 1, and so on. In the case when arg is less than the number of formal parameters for the Function object, this property shares its value with the corresponding property of the activation object. This means that changing this property changes the corresponding property of the activation object and vice versa.
That is just a standard feature of Javascript. Whenever any function is called, there is an arguments array automatically added to the local scope. This allows a function to receive a variable or unknown amount of parameters from the caller, and dynamically use these as necessary.
Commonly this is used when one function is placed as a wrapper around another where the exact parameters are unknown and arbitrary to the wrapper, who simply performs an action and then passes the provided arguments directly into the wrapped function.
arguments is a property of function objects. See Using the arguments object or Property: Function: arguments for more information.
It's worth noting that arguments is not a "real" array, the documentation calls it an "array-like object" - more in Turning JavaScript's arguments object into an array.