The primitive types (number, string, etc.) are passed by value, but objects are unknown, because they can be both passed-by-value (in case we consider that a variable holding an object is in fact a reference to the object) and passed-by-reference (when we consider that the variable to the object holds the object itself).
Although it doesn't really matter at the end, I want to know what is the correct way to present the arguments passing conventions. Is there an excerpt from JavaScript specification, which defines what should be the semantics regarding this?
var x=3, y=x; f(x); alert(y === x);
then function f()
can make the alert report false
and not true
. In JavaScript, that's not possible, so it's not pass-by-reference. It's good that it's possible to pass references to modifiable objects, but that's not what "pass by reference" means. As I said, it's a shame that the terminology is so confusing.
It's interesting in JavaScript. Consider this example:
function changeStuff(a, b, c) { a = a * 10; b.item = "changed"; c = {item: "changed"}; } var num = 10; var obj1 = {item: "unchanged"}; var obj2 = {item: "unchanged"}; changeStuff(num, obj1, obj2); console.log(num); console.log(obj1.item); console.log(obj2.item);
This produces the output:
10
changed
unchanged
If obj1 was not a reference at all, then changing obj1.item would have no effect on the obj1 outside of the function.
If the argument was a proper reference, then everything would have changed. num would be 100, and obj2.item would read "changed". Instead, num stays 10 and obj2.item remains "unchanged".
Instead, the situation is that the item passed in is passed by value. But the item that is passed by value is itself a reference. Technically, this is called call-by-sharing.
In practical terms, this means that if you change the parameter itself (as with num
and obj2
), that won't affect the item that was fed into the parameter. But if you change the internals of the parameter, that will propagate back up (as with obj1
).
It's always pass by value, but for objects the value of the variable is a reference. Because of this, when you pass an object and change its members, those changes persist outside of the function. This makes it look like pass by reference. But if you actually change the value of the object variable you will see that the change does not persist, proving it's really pass by value.
Example:
function changeObject(x) { x = { member: "bar" }; console.log("in changeObject: " + x.member); } function changeMember(x) { x.member = "bar"; console.log("in changeMember: " + x.member); } var x = { member: "foo" }; console.log("before changeObject: " + x.member); changeObject(x); console.log("after changeObject: " + x.member); /* change did not persist */ console.log("before changeMember: " + x.member); changeMember(x); console.log("after changeMember: " + x.member); /* change persists */
Output:
before changeObject: foo
in changeObject: bar
after changeObject: foo
before changeMember: foo
in changeMember: bar
after changeMember: bar
changeObject
, I've changed x
to contain a reference to the new object. x = {member:"bar"};
is equivalent to x = new Object(); x.member = "bar";
What I'm saying is also true of C#, by the way.
ref
keyword you can pass the reference by reference (instead of the default of passing the reference by value), and then the change to point to a new Object()
will persist.
The variable doesn't "hold" the object; it holds a reference. You can assign that reference to another variable, and now both reference the same object. It's always pass by value (even when that value is a reference...).
There's no way to alter the value held by a variable passed as a parameter, which would be possible if JavaScript supported passing by reference.
My two cents... This is the way I understand it. (Feel free to correct me if I'm wrong)
It's time to throw out everything you know about pass by value / reference.
Because in JavaScript, it doesn't matter whether it's passed by value or by reference or whatever. What matters is mutation vs assignment of the parameters passed into a function.
OK, let me do my best to explain what I mean. Let's say you have a few objects.
var object1 = {};
var object2 = {};
What we have done is "assignment"... We've assigned 2 separate empty objects to the variables "object1" and "object2".
Now, let's say that we like object1 better... So, we "assign" a new variable.
var favoriteObject = object1;
Next, for whatever reason, we decide that we like object 2 better. So, we do a little re-assignment.
favoriteObject = object2;
Nothing happened to object1 or to object2. We haven't changed any data at all. All we did was re-assign what our favorite object is. It is important to know that object2 and favoriteObject are both assigned to the same object. We can change that object via either of those variables.
object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe
OK, now let's look at primitives like strings for example
var string1 = 'Hello world';
var string2 = 'Goodbye world';
Again, we pick a favorite.
var favoriteString = string1;
Both our favoriteString and string1 variables are assigned to 'Hello world'. Now, what if we want to change our favoriteString??? What will happen???
favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'
Uh oh.... What has happened. We couldn't change string1 by changing favoriteString... Why?? Because we didn't change our string object. All we did was "RE ASSIGN" the favoriteString variable to a new string. This essentially disconnected it from string1. In the previous example, when we renamed our object, we didn't assign anything. (Well, not to the variable itself, ... we did, however, assign the name property to a new string.) Instead, we mutated the object which keeps the connections between the 2 variables and the underlying objects. (Even if we had wanted to modify or mutate the string object itself, we couldn't have, because strings are actually immutable in JavaScript.)
Now, on to functions and passing parameters.... When you call a function, and pass a parameter, what you are essentially doing is an "assignment" to a new variable, and it works exactly the same as if you assigned using the equal (=) sign.
Take these examples.
var myString = 'hello';
// Assign to a new variable (just like when you pass to a function)
var param1 = myString;
param1 = 'world'; // Re assignment
console.log(myString); // Logs 'hello'
console.log(param1); // Logs 'world'
Now, the same thing, but with a function
function myFunc(param1) {
param1 = 'world';
console.log(param1); // Logs 'world'
}
var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString);
console.log(myString); // logs 'hello'
OK, now let’s give a few examples using objects instead... first, without the function.
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;
// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'
// Now, let's reassign the variable
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';
Now, the same thing, but with a function call
function myFunc(otherObj) {
// Let's mutate our object
otherObj.firstName = 'Sue';
console.log(otherObj.firstName); // Logs 'Sue'
// Now let's re-assign
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
console.log(otherObj.firstName); // Logs 'Jack'
// Again, otherObj and myObject are assigned to 2 very different objects
// And mutating one object doesn't magically mutate the other
}
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);
console.log(myObject.firstName); // Logs 'Sue', just like before
OK, if you read through this entire post, perhaps you now have a better understanding of how function calls work in JavaScript. It doesn't matter whether something is passed by reference or by value... What matters is assignment vs mutation.
Every time you pass a variable to a function, you are "Assigning" to whatever the name of the parameter variable is, just like if you used the equal (=) sign.
Always remember that the equals sign (=) means assignment. Always remember that passing a parameter to a function in JavaScript also means assignment. They are the same and the 2 variables are connected in exactly the same way (which is to say they aren't, unless you count that they are assigned to the same object).
The only time that "modifying a variable" affects a different variable is when the underlying object is mutated (in which case you haven't modified the variable, but the object itself.
There is no point in making a distinction between objects and primitives, because it works the same exact way as if you didn't have a function and just used the equal sign to assign to a new variable.
The only gotcha is when the name of the variable you pass into the function is the same as the name of the function parameter. When this happens, you have to treat the parameter inside the function as if it was a whole new variable private to the function (because it is)
function myFunc(myString) {
// myString is private and does not affect the outer variable
myString = 'hello';
}
var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';
myFunc(myString);
console.log(myString); // Logs 'test'
foo(char *a){a="hello";}
does nothing, but if you do foo(char *a){a[0]='h';a[1]='i';a[2]=0;}
it is changed outside because a
is a memory location passed by value that references a string (char array). Passing structs (similar to js objects) by value in C is allowed, but not recommended. JavaScript simply enforces these best practices and hides the unnecessary and usually undesired cruft... and it sure makes for easier reading.
source = { "id":"1"}; copy = source /*this is wrong*/; copy.id="2"
that source is still {"id":"1"}?
These phrases/concepts were originally defined long before JS was created and they don't accurately describe the semantics for javascript. I think trying to apply them to JS causes more confusion than not.
So don't get hung up on "pass by reference/value".
Consider the following:
Variables are pointers to values. Reassigning a variable merely points that pointer at a new value. Reassigning a variable will never affect other variables that were pointing at that same object because each variable has its own pointer.
So if I had to give it a name I'd say "pass-by-pointer" -- we don't deal with pointers in JS but the underlying engine does.
// code
var obj = {
name: 'Fred',
num: 1
};
// illustration
'Fred'
/
/
(obj) ---- {}
\
\
1
// code
obj.name = 'George';
// illustration
'Fred'
(obj) ---- {} ----- 'George'
\
\
1
// code
obj = {};
// illustration
'Fred'
(obj) {} ----- 'George'
| \
| \
{ } 1
// code
var obj = {
text: 'Hello world!'
};
/* function parameters get their own pointer to
* the arguments that are passed in, just like any other variable */
someFunc(obj);
// illustration
(caller scope) (someFunc scope)
\ /
\ /
\ /
\ /
\ /
{ }
|
|
|
'Hello world'
Some final comments:
The phrases "pass by value/reference" are only used to describe the behavior of a language, not necessarily the actual underlying implementation. As a result of this abstraction, critical details that are essential for a decent explanation are lost, which inevitably leads to the current situation where a single term doesn't adequately describe the actual behavior without additional info.
It's tempting to think that primitives are enforced by special rules while objects are not, but primitives are simply the end of the pointer chain.
As a final example, consider why a common attempt to clear an array doesn't work as expected.
var a = [1, 2]; var b = a; a = []; console.log(b); // [1,2] // doesn't work because `b` is still pointing at the original array
{'George', 1}
values, but only use one of them at a time, then how are the others managed? And what happens when I assign a variable to the value of another variable? Am I then pointing to a pointer, or pointing to the pointee of the right operand? Does var myExistingVar = {"blah", 42}; var obj = myExistingVar;
result in obj
pointing to {"blah", 42}
, or to myExistingVar
?
1)
I ran a memory profile in the browser dev tools for a loop function such as the one you described and saw spikes in memory usage throughout the looping process. This would seem to indicate that new identical objects are indeed being created in each iteration of the loop. When the spikes suddenly fall, the garbage collector just cleaned up a group of these unused objects.
2)
Regarding something like var a = b
, javascript does not provide a mechanism for using pointers and so a variable can never point to a pointer (as you can in C), although the underlying javascript engine undoubtedly uses them. So...var a = b
will point a
"to the pointee of the right operand"
An object outside a function is passed into a function by giving a reference to the outside object.
When you use that reference to manipulate its object, the object outside is thus affected. However, if inside the function you decided to point the reference to something else, you did not affect the object outside at all, because all you did was re-direct the reference to something else.
Think of it like this: It's always pass by value. However, the value of an object is not the object itself, but a reference to that object.
Here is an example, passing a number (a primitive type)
function changePrimitive(val) {
// At this point there are two '10's in memory.
// Changing one won't affect the other
val = val * 10;
}
var x = 10;
changePrimitive(x);
// x === 10
Repeating this with an object yields different results:
function changeObject(obj) {
// At this point there are two references (x and obj) in memory,
// but these both point to the same object.
// changing the object will change the underlying object that
// x and obj both hold a reference to.
obj.val = obj.val * 10;
}
var x = { val: 10 };
changeObject(x);
// x === { val: 100 }
One more example:
function changeObject(obj) {
// Again there are two references (x and obj) in memory,
// these both point to the same object.
// now we create a completely new object and assign it.
// obj's reference now points to the new object.
// x's reference doesn't change.
obj = { val: 100 };
}
var x = { val: 10 };
changeObject(x);
// x === { val: 10}
A very detailed explanation about copying, passing and comparing by value and by reference is in this chapter of the "JavaScript: The Definitive Guide" book.
Before we leave the topic of manipulating objects and arrays by reference, we need to clear up a point of nomenclature. The phrase "pass by reference" can have several meanings. To some readers, the phrase refers to a function invocation technique that allows a function to assign new values to its arguments and to have those modified values visible outside the function. This is not the way the term is used in this book. Here, we mean simply that a reference to an object or array -- not the object itself -- is passed to a function. A function can use the reference to modify properties of the object or elements of the array. But if the function overwrites the reference with a reference to a new object or array, that modification is not visible outside of the function. Readers familiar with the other meaning of this term may prefer to say that objects and arrays are passed by value, but the value that is passed is actually a reference rather than the object itself.
JavaScript is always pass-by-value; everything is of value type.
Objects are values, and member functions of objects are values themselves (remember that functions are first-class objects in JavaScript). Also, regarding the concept that everything in JavaScript is an object; this is wrong. Strings, symbols, numbers, booleans, nulls, and undefineds are primitives.
On occasion they can leverage some member functions and properties inherited from their base prototypes, but this is only for convenience. It does not mean that they are objects themselves. Try the following for reference:
x = "test"; console.log(x.foo); x.foo = 12; console.log(x.foo);
In both console.log
you will find the value to be undefined
.
x = "teste"; x.foo = 12;
etc. Just because a property isn't persistent it doesn't mean it's not an object. As MDN says: In JavaScript, almost everything is an object. All primitive types except null and undefined are treated as objects. They can be assigned properties (assigned properties of some types are not persistent), and they have all characteristics of objects. link
In JavaScript, the type of the value solely controls whether that value will be assigned by value-copy or by reference-copy.
Primitive values are always assigned/passed by value-copy:
null
undefined
string
number
boolean
symbol in ES6
Compound values are always assigned/passed by reference-copy
objects
arrays
function
For example
var a = 2;
var b = a; // `b` is always a copy of the value in `a`
b++;
a; // 2
b; // 3
var c = [1,2,3];
var d = c; // `d` is a reference to the shared `[1,2,3]` value
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]
In the above snippet, because 2
is a scalar primitive, a
holds one initial copy of that value, and b
is assigned another copy of the value. When changing b
, you are in no way changing the value in a
.
But both c
and d
are separate references to the same shared value [1,2,3]
, which is a compound value. It's important to note that neither c
nor d
more "owns" the [1,2,3]
value -- both are just equal peer references to the value. So, when using either reference to modify (.push(4)
) the actual shared array
value itself, it's affecting just the one shared value, and both references will reference the newly modified value [1,2,3,4]
.
var a = [1,2,3];
var b = a;
a; // [1,2,3]
b; // [1,2,3]
// later
b = [4,5,6];
a; // [1,2,3]
b; // [4,5,6]
When we make the assignment b = [4,5,6]
, we are doing absolutely nothing to affect where a
is still referencing ([1,2,3]
). To do that, b
would have to be a pointer to a
rather than a reference to the array
-- but no such capability exists in JS!
function foo(x) {
x.push( 4 );
x; // [1,2,3,4]
// later
x = [4,5,6];
x.push( 7 );
x; // [4,5,6,7]
}
var a = [1,2,3];
foo( a );
a; // [1,2,3,4] not [4,5,6,7]
When we pass in the argument a
, it assigns a copy of the a
reference to x
. x
and a
are separate references pointing at the same [1,2,3]
value. Now, inside the function, we can use that reference to mutate the value itself (push(4)
). But when we make the assignment x = [4,5,6]
, this is in no way affecting where the initial reference a
is pointing -- still points at the (now modified) [1,2,3,4]
value.
To effectively pass a compound value (like an array
) by value-copy, you need to manually make a copy of it, so that the reference passed doesn't still point to the original. For example:
foo( a.slice() );
Compound value (object, array, etc) that can be passed by reference-copy
function foo(wrapper) {
wrapper.a = 42;
}
var obj = {
a: 2
};
foo( obj );
obj.a; // 42
Here, obj
acts as a wrapper for the scalar primitive property a
. When passed to foo(..)
, a copy of the obj
reference is passed in and set to the wrapper
parameter. We now can use the wrapper
reference to access the shared object, and update its property. After the function finishes, obj.a
will see the updated value 42
.
well, it's about 'performance' and 'speed' and in the simple word 'memory management' in a programming language.
in javascript we can put values in two layer: type1-objects
and type2-all other types of value such as string
& boolean
& etc
if you imagine memory as below squares which in every one of them just one type2-value can be saved:
https://i.stack.imgur.com/wFWOsm.png
every type2-value (green) is a single square while a type1-value (blue) is a group of them:
https://i.stack.imgur.com/vwu2vm.png
the point is that if you want to indicate a type2-value, the address is plain but if you want to do the same thing for type1-value that's not easy at all! :
https://i.stack.imgur.com/ZISOHm.png
and in a more complicated story:
https://i.stack.imgur.com/GIEvCm.png
https://i.stack.imgur.com/orhtHm.png
while the green arrow here is a typical variable, the purple one is an object variable, so because the green arrow(typical variable) has just one task (and that is indicating a typical value) we don't need to separate it's value from it so we move the green arrow with the value of that wherever it goes and in all assignments, functions and so on ...
but we cant do the same thing with the purple arrow, we may want to move 'john' cell here or many other things..., so the purple arrow will stick to its place and just typical arrows that were assigned to it will move ...
a very confusing situation is where you can't realize how your referenced variable changes, let's take a look at a very good example:
let arr = [1, 2, 3, 4, 5]; //arr is an object now and a purple arrow is indicating it
let obj2 = arr; // now, obj2 is another purple arrow that is indicating the value of arr obj
let obj3 = ['a', 'b', 'c'];
obj2.push(6); // first pic below - making a new hand for the blue circle to point the 6
//obj2 = [1, 2, 3, 4, 5, 6]
//arr = [1, 2, 3, 4, 5, 6]
//we changed the blue circle object value (type1-value) and due to arr and obj2 are indicating that so both of them changed
obj2 = obj3; //next pic below - changing the direction of obj2 array from blue circle to orange circle so obj2 is no more [1,2,3,4,5,6] and it's no more about changing anything in it but we completely changed its direction and now obj2 is pointing to obj3
//obj2 = ['a', 'b', 'c'];
//obj3 = ['a', 'b', 'c'];
https://i.stack.imgur.com/fELHnm.png
This is little more explanation for pass by value and pass by reference (JavaScript). In this concept, they are talking about passing the variable by reference and passing the variable by reference.
Pass by value (primitive type)
var a = 3;
var b = a;
console.log(a); // a = 3
console.log(b); // b = 3
a=4;
console.log(a); // a = 4
console.log(b); // b = 3
applies to all primitive type in JavaScript (string, number, Boolean, undefined, and null).
a is allocated a memory (say 0x001) and b creates a copy of the value in memory (say 0x002).
So changing the value of a variable doesn't affect the other, as they both reside in two different locations.
Pass by reference (objects)
var c = { "name" : "john" };
var d = c;
console.log(c); // { "name" : "john" }
console.log(d); // { "name" : "john" }
c.name = "doe";
console.log(c); // { "name" : "doe" }
console.log(d); // { "name" : "doe" }
The JavaScript engine assigns the object to the variable c, and it points to some memory, say (0x012).
When d=c, in this step d points to the same location (0x012).
Changing the value of any changes value for both the variable.
Functions are objects
Special case, pass by reference (objects)
c = {"name" : "jane"};
console.log(c); // { "name" : "jane" }
console.log(d); // { "name" : "doe" }
The equal(=) operator sets up new memory space or address
c
is set to a copy of the new object's reference.
Semantics!! Setting concrete definitions will necessarily make some answers and comments incompatible since they are not describing the same thing even when using the same words and phrases, but it is critical to get past the confusion (especially for new programmers).
First of all, there are multiple levels of abstraction that not everyone seems to grasp. Newer programmers who have learned on 4th or 5th generation languages may have difficulty wrapping their mind around concepts familiar to assembly or C programmers not phased by pointers to pointers to pointers. Pass-by-reference does not simply mean the ability to change a referenced object using a function parameter variable.
Variable: Combined concept of a symbol which references a value at a particular location in memory. This term is usually too loaded to be used alone in discussing details.
Symbol: Text string used to refer to variable (i.e. variable's name).
Value: Particular bits stored in memory and referenced using variable's symbol.
Memory location: Where a variable's value is stored. (The location itself is represented by a number separate from the value stored at the location.)
Function parameter: Variable declared in a function definition, used for referencing variables passed to the function.
Function argument: Variable outside the function which is passed to the function by the caller.
Object variable: Variable whose basic underlying value is not the "object" itself, rather its value is a pointer (memory location value) to another location in memory where the object's actual data is stored. In most higher-generation languages, the "pointer" aspect is effectively hidden by automatic de-referencing in various contexts.
Primitive variable: Variable whose value IS the actual value. Even this concept can be complicated by auto-boxing and object-like contexts of various languages, but the general ideas is that the variable's value IS the actual value represented by the variable's symbol rather than a pointer to another memory location.
Function arguments and parameters are not the same thing. Also, a variable's value is not the variable's object (as already pointed out by various people, but apparently ignored). These distinctions are critical to proper understanding.
Pass-by-value or Call-by-sharing (for objects): The function argument's value is COPIED to another memory location which is referenced by the function's parameter symbol (regardless of whether it's on the stack or heap). In other words, the function parameter received a copy of the passed argument's value... AND (critical) the argument's value IS NEVER UPDATED / ALTERED / CHANGED by the calling function. Remember, an object variable's value is NOT the object itself, rather it is the pointer to the object, so passing an object variable by value copies the pointer to the function parameter variable. The function parameter's value points to the exact same object in memory. The object data itself can be altered directly via the function parameter, BUT the function argument's value IS NEVER UPDATED, so it will continue to point to the same object throughout and even after the function call (even if its object's data was altered or if the function parameter is assigned a different object altogether). It is incorrect to conclude that the function argument was passed by reference just because the referenced object is updatable via the function parameter variable.
Call / Pass-by-reference: The function argument's value can/will be updated directly by the corresponding function parameter. If it helps, the function parameter becomes an effective "alias" for the argument--they effectively refer to the same value at the same memory location. If a function argument is an object variable, the ability to change the object's data is no different than the pass-by-value case since the function parameter will still point to the same object as the argument. But in the object variable case, if the function parameter is set to a completely different object, then the argument will likewise also point to the different object--this does not happen in the pass-by-value case.
JavaScript does not pass by reference. If you read closely, you will realize that all contrary opinions misunderstand what is meant by pass-by-value and they falsely conclude that the ability to update an object's data via the function parameter is synonymous to "pass-by-value".
Object clone/copy: A new object is created and the original object's data is copied. This can be a deep copy or shallow copy, but the point is that a new object is created. Creating a copy of an object is a separate concept from pass-by-value. Some languages distinguish between class object and structs (or the like), and may have different behavior for passing variables of the different types. But JavaScript does not do anything like this automatically when passing object variables. But the absence of automatic object cloning does not translate to pass-by-reference.
sharing what I know of references in JavaScript
In JavaScript, when assigning an object to a variable, the value assigned to the variable is a reference to the object:
var a = { a: 1, b: 2, c: 3 }; var b = a; // b.c is referencing to a.c value console.log(b.c) // Output: 3 // Changing value of b.c b.c = 4 // Also changes the value of a.c console.log(a.c) // Output: 4
JavaScript passes primitive types by value and object types by reference
Now, people like to bicker endlessly about whether "pass by reference" is the correct way to describe what Java et al. actually do. The point is this: Passing an object does not copy the object. An object passed to a function can have its members modified by the function. A primitive value passed to a function cannot be modified by the function. A copy is made. In my book that's called passing by reference.
— Brian Bi - Which programming languages are pass by reference?
Update
Here is a rebuttal to this:
There is no "pass by reference" available in JavaScript.
Observation: If there isn't any way for an observer to examine the underlying memory of the engine, there is no way to determine whether an immutable value gets copied or a reference gets passed.
JavaScript is more or less agnostic to the underlying memory model. There is no such thing as a reference². JavaScript has values. Two variables can hold the same value (or more accurate: two environment records can bind the same value). The only type of values that can be mutated are objects through their abstract [[Get]] and [[Set]] operations. If you forget about computers and memory, this is all you need to describe JavaScript's behaviour, and it allows you to understand the specification.
let a = { prop: 1 };
let b = a; // a and b hold the same value
a.prop = "test"; // The object gets mutated, can be observed through both a and b
b = { prop: 2 }; // b holds now a different value
Now you might ask yourself how two variables can hold the same value on a computer. You might then look into the source code of a JavaScript engine and you'll most likely find something which a programmer of the language the engine was written in would call a reference.
So in fact you can say that JavaScript is "pass by value", whereas the value can be shared, and you can say that JavaScript is "pass by reference", which might be a useful logical abstraction for programmers from low level languages, or you might call the behaviour "call by sharing".
As there is no such thing as a reference in JavaScript, all of these are neither wrong nor on point. Therefore I don't think the answer is particularly useful to search for.
² The term Reference in the specification is not a reference in the traditional sense. It is a container for an object and the name of a property, and it is an intermediate value (e.g., a.b
evaluates to Reference { value = a, name = "b" }
). The term reference also sometimes appears in the specification in unrelated sections.
Everything is passed by value.
Basic types are passed by value (i.e. a new copy of the actual variable value is passed to the function).
Complex types (objects) are passed as "pointer to the object". So the actual stuff you are passing is a pointer which is passed by value (it's an address, a numerical value like any other). Obviously if you try to modify a property of the object inside the function, the modification will be reflected even outside of such function. That's because you are accessing the property via the pointer which points to the unique copy of the property.
The confusion here has arises over "passing a pointer by value" and "passing an object by reference".
My simple way to understand this...
When calling a function, you are passing the content (reference or value) of the argument variables, not the the variables themselves. var var1 = 13; var var2 = { prop: 2 }; //13 and var2's content (reference) are being passed here foo(var1, var2);
Inside the function, parameter variables, inVar1 and inVar2, receive the contents being passed. function foo(inVar1, inVar2){ //changing contents of inVar1 and inVar2 won't affect variables outside inVar1 = 20; inVar2 = { prop: 7 }; }
Since inVar2 received the reference of { prop: 2 }, you can change the value of the object's property. function foo(inVar1, inVar2){ inVar2.prop = 7; }
The MDN docs explain it clearly, without being too verbose:
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, (...)
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Description
Passing arguments to a function in JavaScript is analogous to passing parameters by pointer value in C:
/*
The following C program demonstrates how arguments
to JavaScript functions are passed in a way analogous
to pass-by-pointer-value in C. The original JavaScript
test case by @Shog9 follows with the translation of
the code into C. This should make things clear to
those transitioning from C to JavaScript.
function changeStuff(num, obj1, obj2)
{
num = num * 10;
obj1.item = "changed";
obj2 = {item: "changed"};
}
var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
changeStuff(num, obj1, obj2);
console.log(num);
console.log(obj1.item);
console.log(obj2.item);
This produces the output:
10
changed
unchanged
*/
#include <stdio.h>
#include <stdlib.h>
struct obj {
char *item;
};
void changeStuff(int *num, struct obj *obj1, struct obj *obj2)
{
// make pointer point to a new memory location
// holding the new integer value
int *old_num = num;
num = malloc(sizeof(int));
*num = *old_num * 10;
// make property of structure pointed to by pointer
// point to the new value
obj1->item = "changed";
// make pointer point to a new memory location
// holding the new structure value
obj2 = malloc(sizeof(struct obj));
obj2->item = "changed";
free(num); // end of scope
free(obj2); // end of scope
}
int num = 10;
struct obj obj1 = { "unchanged" };
struct obj obj2 = { "unchanged" };
int main()
{
// pass pointers by value: the pointers
// will be copied into the argument list
// of the called function and the copied
// pointers will point to the same values
// as the original pointers
changeStuff(&num, &obj1, &obj2);
printf("%d\n", num);
puts(obj1.item);
puts(obj2.item);
return 0;
}
For programming language lawyers, I've went through the following sections of ECMAScript 5.1 (which is easier to read than the latest edition), and go as far as asking it on the ECMAScript mailing list.
TL;DR: Everythings're passed by value, but properties of Objects are references, and the definition of Object is creepily lacking in the standard.
Construction of Argument Lists
Section 11.2.4 "Argument Lists" says the following on producing a argument list consisting of only 1 argument:
The production ArgumentList : AssignmentExpression is evaluated as follows: Let ref be the result of evaluating AssignmentExpression. Let arg be GetValue(ref). Return a List whose sole item is arg.
The section also enumerate cases where argument list has 0 or >1 arguments.
Thus, everything's are passed by reference.
Access of Object Properties
Section 11.2.1 "Property Accessors"
The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows: Let baseReference be the result of evaluating MemberExpression. Let baseValue be GetValue(baseReference). Let propertyNameReference be the result of evaluating Expression. Let propertyNameValue be GetValue(propertyNameReference). Call CheckObjectCoercible(baseValue). Let propertyNameString be ToString(propertyNameValue). If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.
Thus, properties of Objects are always available as reference.
On Reference
It is described in section 8.7 "The Reference Specification Type", that references are not real types in the language - they're only used to describe the behavior of the delete, the typeof, and the assignment operators.
Definition of "Object"
It is defined in 5.1 edition that "An Object is a collection of properties". Therefore, we can infer, that the value of the object is the collection, but as to what is the value of the collection is poorly defined in the spec, and requires a bit of effort to understand.
a.b = 1
is able to know which object (a
) the property (b
) gets set on (cause a.b
evaluates to the Reference { a, "b" }
).
The most succinct explanation I found was in the AirBNB style guide:
Primitives: When you access a primitive type you work directly on its value string number boolean null undefined
string
number
boolean
null
undefined
E.g.:
var foo = 1,
bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
Complex: When you access a complex type you work on a reference to its value object array function
object
array
function
E.g.:
var foo = [1, 2],
bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
I.e. effectively primitive types are passed by value, and complex types are passed by reference.
I've read through these answers multiple times, but didn't REALLY get it until I learned about the technical definition of "Call by sharing" as termed by Barbara Liskov
The semantics of call by sharing differ from call by reference in that assignments to function arguments within the function aren't visible to the caller (unlike by reference semantics)[citation needed], so e.g. if a variable was passed, it is not possible to simulate an assignment on that variable in the caller's scope. However, since the function has access to the same object as the caller (no copy is made), mutations to those objects, if the objects are mutable, within the function are visible to the caller, which may appear to differ from call by value semantics. Mutations of a mutable object within the function are visible to the caller because the object is not copied or cloned — it is shared.
That is, parameter references are alterable if you go and access the parameter value itself. On the other hand, assignment to a parameter will disappear after evaluation, and is non-accessible to the function caller.
In a low-level language, if you want to pass a variable by reference, you have to use a specific syntax in the creation of the function:
int myAge = 14;
increaseAgeByRef(myAge);
function increaseAgeByRef(int &age) {
*age = *age + 1;
}
The &age
is a reference to myAge
, but if you want the value you have to convert the reference, using *age
.
JavaScript is a high level language that does this conversion for you.
So, although objects are passed by reference, the language converts the reference parameter to the value. You don't need to use &
, on the function definition, to pass it by reference, neither *
, on the function body, to convert the reference to the value, JavaScript does it for you.
That's why when you try to change an object inside a function, by replacing it's value (i.e. age = {value:5}
), the change doesn't persist, but if you change it's properties (i.e. age.value = 5
), it does.
myAge
. You can't do that in JavaScript. You can change properties an on object myAge
references but you can't not change myAge
the variable itself. That is what "pass by reference' means, to be able to change the value of a variable outside the function.
If you want (normal) function parameter behavior like in other languages (passing copy of a value) then just clone the object before passing into a function:
function run()
{
var test = [];
test.push(1);
console.log('before: '+test); // 1
changeVariable(_.clone(test)); // (Note: I am using lodash _.clone() function)
console.log('after: '+test); // 1
}
function changeVariable(test2) {
var test1 = test2;
test1.push(2);
console.log('inside func:', test1); // inside func: [1,2]
}
run();
I have found the extend method of the Underscore.js library very useful when I want to pass in an object as a parameter which may either be modified or replaced entirely.
function replaceOrModify(aObj) {
if (modify) {
aObj.setNewValue('foo');
} else {
var newObj = new MyObject();
// _.extend(destination, *sources)
_.extend(newObj, aObj);
}
}
I would say it is pass-by-copy -
Consider arguments and variable objects are objects created during the execution context created in the beginning of function invocation - and your actual value/reference passed into the function just get stored in this arguments + variable objects.
Simply speaking, for primitive types, the values get copied in the beginning of function call, for object type, the reference get copied.
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.key1= "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
An easy way to determine whether something is "pass by reference" is whether you can write a "swap" function. For example, in C, you can do:
void swap(int *i, int *j)
{
int t;
t = *i;
*i = *j;
*j = t;
}
If you can't do the equivalent of that in JavaScript, it is not "pass by reference".
Primitives (number, Boolean, etc.) are passed by value. Strings are immutable, so it doesn't really matter for them. Objects are passed by reference (the reference is passed by value).
Success story sharing
item
property of the object referenced by obj1, you are changing the value of the item property that was originally set to "unchanged". When you assign obj2 a value of {item: "changed"} you are changing the reference to a new object (which immediately goes out of scope when the function exits). It becomes more apparent what's happening if you name the function params things like numf, obj1f, and obj2f. Then you see that the params were hiding the external var names.ref
keyword.) Usually you would just have the function return the new object, and do the assignment at the point where you call the function. E.g.,foo = GetNewFoo();
instead ofGetNewFoo(foo);
var obj1 = { item: 'unchanged' }; var obj2 = obj1; obj2.item = 'changed';
and would observe the same effect as in your example. Therefore I personally refer the answer of Tim Goodman