This question already has answers here:
Is JavaScript a pass-by-reference or pass-by-value language?
(33 answers)
Closed 8 years ago.
I'm looking for some good comprehensive reading material on when JavaScript passes something by value and when by reference and when modifying a passed item affects the value outside a function and when not. I'm also interested in when assigning to another variable is by reference vs. by value and whether that follows any different rules than passing as a function parameter.
I've done a lot of searching and find lots of specific examples (many of them here on SO) from which I can start to piece together pieces of the real rules, but I haven't yet found a single, well written document that describes it all.
Also, are there ways in the language to control whether something is passed by reference or by value?
Here are some of the types of questions I want to understand. These are just examples - I'm actually looking to understand the rules the language goes by, not just the answers to specific examples. But, here are some examples:
function f(a,b,c) {
a = 3;
b.push("foo");
c.first = false;
}
var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);
When are the contents of x, y and z changed outside the scope of f for all the different types?
function f() {
var a = ["1", "2", "3"];
var b = a[1];
a[1] = "4";
// what is the value of b now for all possible data types that the array in "a" might hold?
}
function f() {
var a = [{yellow: "blue"}, {red: "cyan"}, {green: "magenta"}];
var b = a[1];
a[1].red = "tan";
// what is the value of b now and why?
b.red = "black";
// did the value of a[1].red change when I assigned to b.red?
}
If I want to make a fully independent copy of an object (no references whatsoever), what's the best practice way to do that?
My understanding is that this is actually very simple:
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.
So, to work through some of your examples:
function f(a,b,c) {
// Argument a is re-assigned to a new value.
// The object or primitive referenced by the original a is unchanged.
a = 3;
// Calling b.push changes its properties - it adds
// a new property b[b.length] with the value "foo".
// So the object referenced by b has been changed.
b.push("foo");
// The "first" property of argument c has been changed.
// So the object referenced by c has been changed (unless c is a primitive)
c.first = false;
}
var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);
console.log(x, y, z.first); // 4, ["eeny", "miny", "mo", "foo"], false
Example 2:
var a = ["1", "2", {foo:"bar"}];
var b = a[1]; // b is now "2";
var c = a[2]; // c now references {foo:"bar"}
a[1] = "4"; // a is now ["1", "4", {foo:"bar"}]; b still has the value
// it had at the time of assignment
a[2] = "5"; // a is now ["1", "4", "5"]; c still has the value
// it had at the time of assignment, i.e. a reference to
// the object {foo:"bar"}
console.log(b, c.foo); // "2" "bar"
Javascript always passes by value. However, if you pass an object to a function, the "value" is really a reference to that object, so the function can modify that object's properties but not cause the variable outside the function to point to some other object.
An example:
function changeParam(x, y, z) {
x = 3;
y = "new string";
z["key2"] = "new";
z["key3"] = "newer";
z = {"new" : "object"};
}
var a = 1,
b = "something",
c = {"key1" : "whatever", "key2" : "original value"};
changeParam(a, b, c);
// at this point a is still 1
// b is still "something"
// c still points to the same object but its properties have been updated
// so it is now {"key1" : "whatever", "key2" : "new", "key3" : "newer"}
// c definitely doesn't point to the new object created as the last line
// of the function with z = ...
Yes, Javascript always passes by value, but in an array or object, the value is a reference to it, so you can 'change' the contents.
But, I think you already read it on SO; here you have the documentation you want:
http://snook.ca/archives/javascript/javascript_pass
Primitive type variable like string,number are always pass as pass
by value.
Array and Object is passed as pass by reference or pass by value based on these two condition.
if you are changing value of that Object or array with new Object or Array then it is pass by Value.
object1 = {item: "car"};
array1=[1,2,3];
here you are assigning new object or array to old one.you are not changing the value of property
of old object.so it is pass by value.
if you are changing a property value of an object or array then it is pass by Reference.
object1.item= "car";
array1[0]=9;
here you are changing a property value of old object.you are not assigning new object or array to old one.so it is pass by reference.
Code
function passVar(object1, object2, number1) {
object1.key1= "laptop";
object2 = {
key2: "computer"
};
number1 = number1 + 1;
}
var object1 = {
key1: "car"
};
var object2 = {
key2: "bike"
};
var number1 = 10;
passVar(object1, object2, number1);
console.log(object1.key1);
console.log(object2.key2);
console.log(number1);
Output: -
laptop
bike
10
Related
This question already has answers here:
Is JavaScript a pass-by-reference or pass-by-value language?
(33 answers)
Closed 8 years ago.
I'm looking for some good comprehensive reading material on when JavaScript passes something by value and when by reference and when modifying a passed item affects the value outside a function and when not. I'm also interested in when assigning to another variable is by reference vs. by value and whether that follows any different rules than passing as a function parameter.
I've done a lot of searching and find lots of specific examples (many of them here on SO) from which I can start to piece together pieces of the real rules, but I haven't yet found a single, well written document that describes it all.
Also, are there ways in the language to control whether something is passed by reference or by value?
Here are some of the types of questions I want to understand. These are just examples - I'm actually looking to understand the rules the language goes by, not just the answers to specific examples. But, here are some examples:
function f(a,b,c) {
a = 3;
b.push("foo");
c.first = false;
}
var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);
When are the contents of x, y and z changed outside the scope of f for all the different types?
function f() {
var a = ["1", "2", "3"];
var b = a[1];
a[1] = "4";
// what is the value of b now for all possible data types that the array in "a" might hold?
}
function f() {
var a = [{yellow: "blue"}, {red: "cyan"}, {green: "magenta"}];
var b = a[1];
a[1].red = "tan";
// what is the value of b now and why?
b.red = "black";
// did the value of a[1].red change when I assigned to b.red?
}
If I want to make a fully independent copy of an object (no references whatsoever), what's the best practice way to do that?
My understanding is that this is actually very simple:
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.
So, to work through some of your examples:
function f(a,b,c) {
// Argument a is re-assigned to a new value.
// The object or primitive referenced by the original a is unchanged.
a = 3;
// Calling b.push changes its properties - it adds
// a new property b[b.length] with the value "foo".
// So the object referenced by b has been changed.
b.push("foo");
// The "first" property of argument c has been changed.
// So the object referenced by c has been changed (unless c is a primitive)
c.first = false;
}
var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);
console.log(x, y, z.first); // 4, ["eeny", "miny", "mo", "foo"], false
Example 2:
var a = ["1", "2", {foo:"bar"}];
var b = a[1]; // b is now "2";
var c = a[2]; // c now references {foo:"bar"}
a[1] = "4"; // a is now ["1", "4", {foo:"bar"}]; b still has the value
// it had at the time of assignment
a[2] = "5"; // a is now ["1", "4", "5"]; c still has the value
// it had at the time of assignment, i.e. a reference to
// the object {foo:"bar"}
console.log(b, c.foo); // "2" "bar"
Javascript always passes by value. However, if you pass an object to a function, the "value" is really a reference to that object, so the function can modify that object's properties but not cause the variable outside the function to point to some other object.
An example:
function changeParam(x, y, z) {
x = 3;
y = "new string";
z["key2"] = "new";
z["key3"] = "newer";
z = {"new" : "object"};
}
var a = 1,
b = "something",
c = {"key1" : "whatever", "key2" : "original value"};
changeParam(a, b, c);
// at this point a is still 1
// b is still "something"
// c still points to the same object but its properties have been updated
// so it is now {"key1" : "whatever", "key2" : "new", "key3" : "newer"}
// c definitely doesn't point to the new object created as the last line
// of the function with z = ...
Yes, Javascript always passes by value, but in an array or object, the value is a reference to it, so you can 'change' the contents.
But, I think you already read it on SO; here you have the documentation you want:
http://snook.ca/archives/javascript/javascript_pass
Primitive type variable like string,number are always pass as pass
by value.
Array and Object is passed as pass by reference or pass by value based on these two condition.
if you are changing value of that Object or array with new Object or Array then it is pass by Value.
object1 = {item: "car"};
array1=[1,2,3];
here you are assigning new object or array to old one.you are not changing the value of property
of old object.so it is pass by value.
if you are changing a property value of an object or array then it is pass by Reference.
object1.item= "car";
array1[0]=9;
here you are changing a property value of old object.you are not assigning new object or array to old one.so it is pass by reference.
Code
function passVar(object1, object2, number1) {
object1.key1= "laptop";
object2 = {
key2: "computer"
};
number1 = number1 + 1;
}
var object1 = {
key1: "car"
};
var object2 = {
key2: "bike"
};
var number1 = 10;
passVar(object1, object2, number1);
console.log(object1.key1);
console.log(object2.key2);
console.log(number1);
Output: -
laptop
bike
10
let a = 7;
a = 3;
console.log(a); // output 3
In this case, the value 7 is still inside a memory? I was reading that all primitive data types are immutable.
The value of a is kept in memory, until garbage collection eventually recycles it. What the docs mean by immutable is that you can't directly alter the primative (in this case the integer 7). You can only replace the value.
There are examples on the docs but this is another one
let a = 1;
a.toString() // a is still 1, it cannot be mutated
However, we can assign this to another variable
let a = 1;
let b = a.toString() // b is string "1" and a remains as the integer 1
Or we can replace the value
let a = 1;
a = 10; // a is 10
Short answer: no.
Immutable is about the behaviour of the value, not about what happens when it's no longer being references: you cannot change an immutable value, you have to instead reassign your variable if you want it to point to a new value.
let b = 3;
let a = b; // the variable "a" points to the primitive value 3
b = 7; // the variable "a" still points to the primitive value 3
a = 7; // and now it points to a _different_ value. 7, in this case.
This is in contrast to things like arrays or objects, which you can change as much as you like without needing to reassign:
const obj = {};
const a = obj;
obj.cat = `meow`;
console.log(a); // this will show that "a" is { cat: "meow" }
We just changed the content of the value that "a" points to, without any reassignments.
As far as I know, the arrays and objects always act as pointers and just point to somewhere a memory location.
In the following example, as var a is updated, so as b pointing to same memory location as a, should also be updated and final answer should be true, true.
Why is it not happening??? At what instance of time, b gets a different pointer than a and why???
Example:
var a = [2,3,5];
var b = a;
a = [33,45];
console.log(a,b);
console.log(a==b,a===b);
However, to support my clause kindly look at following unchanged values example. Here I am sure both a and b point to same memory location containing data as [2,3,5]. They got same values and are always equated as true.
var a = [2,3,5];
var b = a;
console.log(a==b,a===b);
Because you are not updating the reference of the new object [33, 45].
Following code might help you understand better.
a = [{'a': 1}, {'b': 2}];
b = a;
console.log(a, b);
// creates new object and assigns to the same variable
b = b.concat ([{'c': 3}]);
console.log(a, b);
// but property of object is still referenced in by a and b
b[0].a = 100;
console.log(a,b);
a[2].c = 100; // throws exception, because 'a' does not have the reference to object which refers the object created in 'b'
console.log(a,b);
look at blow:
var a = [2,3,5];
var b = a;
and after the a = [33,45];
the pointer is point to a new obj, not the obj changed
Why is a.y undefined after I change the reference of a in the function?
var a = { x : 1 };
a = { y : 2 };
function _change(b) {
b = { y : 3 };
return b;
}
_change(a);
document.write(a.y); // undefined
document.write(a.x); //1
And the below code behaves differently
var a = {x:1};
var b={y:1};
b=a;
a.x //undefined
a.y //1
Why?
Because you're totally changing the a object {x:1} with {y:2} so there's no x property in a object.
What I think is you need to use like this:
var a = {x:1};
a.y = 2;//assign y = 2 in a oject.
So, do the same manner in your change function.
First Block
This is what I get by running the code line by line:
var a = {x:1}; // <-- sets a to the object {x:1}
a = {y:2}; // <-- sets a to the object {y:2}, so it no longer has a.x = 1
function _change(b)
{
b= { y:3};
return b;
}
_change(a); // <-- this doesn't change a, it returns {y: 3} but it is not used
document.write(a.y); // 2 actually
document.write(a.x); // undefined
Let's try to understand it...
var a = {x:1};
There you declare the variable a, you create an object {x:1}, and set a to that object.
a = {y:2};
There you create a new object {y:2} and set a to it. So a no longer has the first object.
So... when you ask for a.y it has 2, and when you ask for a.x it is undefined because the object {y:2} doesn't have x. Remember that you replaced the object of the variable a from being {x:1} to {y:2}.
Instead you can add fields on the fly, like this:
var a = {x:1}; // <-- sets a to the object {x:1}
a.y = 2; // <-- Add a field y to the object of the variable a, it has the value 2
function _change(b)
{
b.y = 3; // <-- actually modify the object, now the field y has value 3
return b;
}
_change(a);
document.write(a.y); // 3
document.write(a.x); // 1
Second Block
Again, I get a different result than you... I wonder where are you running your code.
var a = {x:1}; // <-- sets a to the object {x:1}
var b={y:1}; // <-- sets b to the object {y:1}
b=a; // <-- now sets b to the object {x:1} - nobody has {y:1} anymore
document.write(a.x); // 1 actually
document.write(a.y); // undefined
Ok, so when you say b=a you are making the variable b to point to the same object as the variable a. By doing so, the variable b no longer points to the object {x:1}... which is irrelevant because you are not using the variable b anyway.
The variable a had {x:1} all along, and you can see it doesn't have any field y defined.
It seems to be that you believe that assigning an object somehow fuses the objects, resulting in both sides having a combination of the fields... if you intend to do that, you may be interested in How can I merge properties of two JavaScript objects dynamically?.
You need to break this down and understand the variables in different lexical scopes.
a in the global lexical scope:
var a = {x:1};
a = {y:2};
The above initialization would resolve to:
a = {y:2};
//hence at this global lexical scope
//`lexicalscope = {"a":{y:2}};`
Now, let us see the variables inside the lexical scope of the function:
function _change(b){
// at the function's `lexicalEnvironment = {"b":{y:2}}`
b= { y:3};
// at this point `lexicalEnvironment = {"b":{y:3}}`
return b; //returned {y:3}.
}
When the function is invoked with a as its parameter.
_change(a); // obtained {y:3} but not captured.
I would love to include the beautiful explanation for why the value of a does not change outside the scope of the function in this answer here, but, do not want to duplicate the original answer. Would like to share the relevant part though,
In practical terms, this means that if you change the parameter itself (as with a),
that won't affect the item that was fed
into the parameter. But if you change the INTERNALS of the parameter, such as b.y = 3,
that will propagate back up.
Again, printing their values in the global lexical scope.
console.log(a.y); // still in the global lexical environment a.y = 2;
console.log(a.x); // `a.x` is undefined in the global Lexical Environment.
As I understand objects are passed by reference in JavaScript (and primitives are passed by value?).
var a, b;
a = {
Foo: "Bar"
}
b = a;
a.Foo = "Other";
console.log(b.Foo); // "Other"
This worked similarly with arrays but did not work like I expect with functions:
var a, b;
a = function(){ return 20; }
b = a;
a = function(){ return 40; }
console.log(b()); // returns 20 ?
I'm confused because I thought functions are objects. Shouldn't the above example return 40?
In the first case, a.Foo = ..., You are changing the value of a property in the object, referred by both a and b. This is called mutating an object.
But in the second case, you are making a refer a new function object. Now, a and b are referring to different function objects.
That is why you are getting 20 in the second case.
First regarding the question in the title (which is actually different from what you demonstrate with the code examples):
"As I understand objects are passed by reference in JavaScript"
No, Javascript doesn't support passing parameter by reference at all. All parameters are passed by value, but the value can be a reference.
Example:
var a = { answer: 42 };
function f(x) {
alert(x.answer); // shows 42
x = { answer: 0 };
alert(x.answer); // shows 0
}
f(a);
alert(a.answer); // shows 42
As the parameter is passed by value, the variable x is separate from the variable a, so assigning a new object to x doesn't change the value of a.
Back to your code:
When you assign an object reference from a variable to another, it's the reference that is copied, not the object. You get two variables that reference the same object.
Either of the variables can be used to access members in the object, which your first code example demonstrates.
If you assign a new object to the first variable, you will replace the reference in the variable, you will not overwrite the object that it currently points to. The object is still intact, and the second variable still points to it. You get two variables that point to one object each, which your second code example demonstrates.
Further to #thefoutheye's answer, consider the following proof of your statement functions are objects:
var a, b;
a = function() { return 20; }
a.Foo = "Bar";
b = a;
a.Foo = "Other";
console.log(b.Foo); // "Other"
You are reassigning the variable a to a new function. That's not the same as changing a property value.
Try:
var a, b;
a = {Foo: function() {return 20;}};
b = a;
a.Foo = function() {return 40;};
console.log(b()); // returns 40