Background
This is a part of a series of writing a tutorial of what I learn everyday. I try to learn something new related to CS and programming everyday and I believe that writing some sort of post, report, or tutorial from memory really solidifies the understanding and makes it stick in your brain.
Today I learned...
How to utilize the spread operator and how copying objects in Javascript work.
What do you think the code below will output?
let obj = {
prim: 2,
anotherObj: {
val: 'red'
}
}
let truck = { ...obj }
truck.anotherObj.val = 'blue'
console.log(truck.anotherObj.val)
console.log(obj.anotherObj.val)
It turns out that the "val" within "anotherObj for both truck and obj will be "blue". This is a bit confusing since shouldn't the two objects be separate since they are stored in separate variables?
Deep vs Shallow Copy
In Javascript, all primitive types are assigned and passed by value, but all objects are assigned and passed by reference. This explains why in the previous code block changing the value of a property of an object resulted in the copy of the object to have its property updated as well.
let obj = {
prim: 2,
anotherObj: {
val: 'red'
}
}
let truck = { ...obj }
truck.prim = 123123
console.log(truck.prim) // 123123
console.log(obj.prim) // 2
In this case since we are modifying the "prim" property which is a primitive type it is not reflected across the other object since in Javascript, primitive types are assigned by value not reference.
What does by reference mean?
Passing or assigning by reference means that when copied the new variable holds a reference or "points" to the space in memory where the original object lies. This means that any changes to either the original object or anything that references it changes the values within the original object.
Shallow copies
Using the spread operator or Object.assign() you can create shallow copies of objects!
let obj1 = {
testing: 'testing'
nestedObj: {
nestedTesting: 'nestedTesting'
}
}
let obj2 = { ...obj1 }
As seen above, the spread operator is "...".
Deep copies
When another object is created with a deep copy, any nested objects are newly created so they don't share the same reference. This means that changes to the copy of the object are not reflected in the original object since a new object is created for the copy.
A way to perform a deep copy is to use the lodash clonedeep package.
Merging Objects
Merging objects can also be performed with the spread operator.
let obj1 = {
name: 'obj1',
testing() {
console.log(this.name)
}
}
let obj2 = {
name2: 'obj2',
testing2() {
console.log(this.name)
}
}
const obj3 = {...obj1, ...obj2} // obj3 has all of the properties in both obj1 and obj2
A thing to note is that if there are properties with the same name in the objects, the value of the last object with that property gets assigned.
Top comments (24)
Objects are not assigned and passed by reference.
Consider the following example.
If objects were assigned and passed by reference then the output would be { "name":"v" } since under pass-by-reference semantics, the parameter and the argument would refer to the same thing.
The output is { "name":"a" } because Javascript does not have pass-by-reference semantics.
a is passed by value.
The confusion comes from thinking that the properties of an object are part of the value of the object, which is the case in C++, but not in Javascript.
In Javascript the value of an object allows you to access the properties associated with that object, and it is these properties that may be mutable.
And, naturally, if you pass the value of an object to something, that something can now access and potentially change those properties.
They are passed by value, just like the other primitive values.
"They are passed by value, just like the other primitive values." That is incorrect.
JavaScript has pass-by-reference, only difference to C++ is it is pass by "copy of reference". Do not alter terminology
I'm not the one altering terminology here.
Passing a copy of a reference wouldn't be pass-by-reference, in any case.
en.wikipedia.org/wiki/Evaluation_s...
"Call by reference (or pass by reference) is an evaluation strategy where a function receives an implicit reference to a variable used as argument, rather than a copy of its value."
Your peculiar "copy-of-a-reference" notion fails to satisfy this requirement.
"This typically means that the function can modify (i.e., assign to) the variable used as argument—something that will be seen by its caller."
And you may note that Javascript doesn't permit this foo(a) cannot change the value of the variable a for the caller.
Next you may review the ecmascript standard.
ecma-international.org/publication...
See: 12.3.6.2 Runtime Semantics: EvaluateCall
And note that it passes values, not references (or even copies of references).
Javascript does have references -- For example in delete a.b; a.b is a reference -- but they are not references to objects; they are references to properties.
I am glad that you put some links, usually, so much opinions going on in discussions.
ECMA also says value of object reference in your link.
"Object references are values"
developer.mozilla.org/en-US/docs/W...
Good explanation here as well:
stackoverflow.com/questions/131044...
Another:
w3schools.com/js/js_function_param...
Agreeing on object property part, but calling function by value of object is not true.
ECMA never mentions 'object references' anywhere.
It mentions 'object values', and explains how they allow you to access the properties associated with that object value.
See '7.3 Operations on Objects' to understand how object values are used to access object properties (and note the complete lack of 'object references').
Mozilla is describing how their implementation works, not specifying the language.
Mozilla implements objects using a value that refers to a structure somewhere, and they call this value an 'object reference' because it is a value that refers to an object.
This has nothing to do with how the language is specified, or with pass-by-reference.
It is passing a value (which happens to refer to some kind of object structure in their implementation) as a value.
Yes -- you can break the comments down into two categories.
What you may note is consistent is that they all agree that javascript passes-by-value. :)
"Arguments are Passed by Value
The parameters, in a function call, are the function's arguments.
JavaScript arguments are passed by value: The function only gets to know the values, not the argument's locations.
If a function changes an argument's value, it does not change the parameter's original value."
They got this bit right. :)
"Objects are Passed by Reference
In JavaScript, object references are values.
Because of this, objects will behave like they are passed by reference:
If a function changes an object property, it changes the original value."
The only way to resolve these two assertions is that javascript is, again, pass-by-value.
They're just confusing the ability to change a property via an object value with meaning that there's somehow a magical reference value to that object.
It's much simpler than that -- let's go back to the standard.
Get(objectValue, propertyKey)
foo.bar is just equivalent to calling Get with the object value and a property key.
No object reference value nonsense -- just simple values.
Incorrect, and I don't understand why you are complicating this stuff.
If you are not sending copy of value, you are sending its reference.
I'm not complicating it.
Here is a simple piece of code.
If foo(a) passes by reference, it will print 1.
If foo(a) passes by value it will print 0.
It's as simple as that.
Guess what gets printed in javascript? :)
Now, let's try this with an object to show that it works exactly the same way
Guess what gets printed this time? :)
It is passing "Copy of Reference", not the copy of value
What about this?
Then it isn't pass-by-reference, is it? :)
Now see if you can find where the ecmascript standard that defines the language refers to object values as references, because I certainly can't.
In your example, you pass the value of a by value to assign and assign it to b.
You can replace assign(a) with b = a;
You then use the value of a to find a property named 'test' and assign it the value true.
You then use the value of b to find the properties associated with that object value and serialize them as JSON.
Note that a === b, so naturally you'll find the same properties when looking up via a or via .
What you may notice is there there's no nonsense about references -- you're just using object values to look up and modify properties.
And that those properties are not part of the value of the object.
There is a reason that the runtime copies reference instead of using original, and still falls in pass-by-reference.
Are you suggesting the runtime makes a copy of
a
and call function ofassign(a)
?That's exactly what I am explicitly stating.
foo(a) passes a copy of the value of a, regardless of the type of a.
Note that properties are not part of the value of an object, which is where I think you're getting confused.
Again, you are altering terminology in Computer Science; if you are not copying entire
a
with its properties, it is not pass-by-value.Sure it is -- those properties aren't part of the object value, and may only be associated by prototypical chaining.
And you may note Scheme in the link you provided -- scheme is pass-by-value but does not copy indirect properties.
Once again, the critical test for pass-by-reference is if changes to the parameter are reflected in the argument.
If it isn't, then it isn't pass-by-reference, and it's clearly in the case in Javascript.
Have you managed to find any mention of 'object reference' in the ecmascript standard yet? :)
Actually, yes, it does:
12.3.6.2 Runtime Semantics: EvaluateCall
6.2.4 The Reference Specification Type
A Reference is a resolved name or property binding. A Reference consists of three components, the base value
component, the referenced name component, and the Boolean-valued strict reference flag. The base value component
is either undefined, an Object, a Boolean, a String, a Symbol, a Number, a BigInt, or an Environment Record. A base
value component of undefined indicates that the Reference could not be resolved to a binding. The referenced name
component is a String or Symbol value.
See this bit here?
Not an object.
An example of using a reference in Javascript is
delete a.b;
where a.b is a reference to a property to be deleted.
I suggest re-reading the section more carefully -- but you are at least on the right track to figuring this out properly. :)
You got so confused "base value" of the the runtime with "primitive value" in ECMA, but my real problem is you are not able to fundamentally distinguish between pass-by-value and pass-by-reference with pure Computer Science terminologies, then I can explain why do they copy references.
Again, it is quite straightforward:
We use the same concept with message brokers in event driven design, which follows same principles.
Read the algorithm in the ecmascript specification.
Show the part which has a(b) copy a reference. :)
In the process you may come to understand what's happening here and perhaps you'll even come to understand what pass-by-reference means.
Good luck.
12.3.6.2 talking about steps of reference check with different types, and it is super clear.
But I want to back off a bit, can we get at least some consensus on "if you are not sending snapshot of entire object, it is not pass-by-value" theorem, I want to make sure you know what that is, then I promise I'll get you all details one by one.
"if you are not sending snapshot of entire object, it is not pass-by-value" is obviously wrong.
Now, since it's not obviously wrong to you, let's go over some of the reasons. :)
Pass by value is about the value
So, what is the value?
Let's consider some operations that operate on values.
Please note any of these that you disagree with, and I'll point you at the section of the specification to explain why you're mistaken.
'snapshot of the entire object'
This is fundamentally incoherent -- what are the boundaries of an object?
Is it the reachable sub-graph of values given that object?
(In which case your argument will be that C++ does not support pass-by-value, since it doesn't necessarily copy these or consider them as part of the value)
Is it the immediate properties of the object?
(In which case your argument will be that C++ does not support pass-by-value, since it doesn't necessarily copy these or consider them as part of the value)
Is it something else? Feel free to propose some definition for 'entire snapshot'.
What pass-by-value and pass-by-reference actually mean
So, let's talk about how values work in C++.
C++ supports pass-by-value by requiring the programmer to establish a coherent protocol of copy and comparison operations.
This means that a = b; changes a such that a == b is true. And that given a == b; foo(a); cannot cause a != b to become true without involving side-effects.
This is what pass-by-value means.
C++ also supports pass-by-reference. In these cases foo(a) can cause a != b to become true, because the argument a and the parameter a in foo are effectively the same object.
So, which of these reflects how Javascript works?
If you say it reflects how C++ does pass-by-reference, it's trivial to disprove given the examples I've shown earlier.
Which is presumably why you keep on talking about 'pass-a-copy-of-a-reference'. I hope that it's clear that whatever you're calling it, it isn't pass-by-reference.
If not, I'll be happy to point out why you're mistaken -- just make a claim about the language specification or program behavior.
Good luck.
Gods of Coffee Mugs say you are so complicating such a simple concept :)
Let me know if you manage to produce a cogent response to any of the issues I've raised.
It is obvious to me and at least 791 people on first page.
stackoverflow.com/questions/131044...
Truth is not a popularity contest.
This is not a cogent response.
Let me know if you come up with one. :)
Honestly, I don't know where to begin for someone fails to understand Wikipedia-level concept
..and it is high school argument