Does JavaScript pass by reference? [duplicate]
Asked Answered
F

13

482

Does JavaScript pass by references or pass by values?

Here is an example from JavaScript: The Good Parts. I am very confused about the my parameter for the rectangle function. It is actually undefined, and redefined inside the function. There are no original reference. If I remove it from the function parameter, the inside area function is not able to access it.

Is it a closure? But no function is returned.

var shape = function (config) {
    var that = {};
    that.name = config.name || "";
    that.area = function () {
        return 0;
    };
    return that;
};

var rectangle = function (config, my) {
    my = my || {};
    my.l = config.length || 1;
    my.w = config.width || 1;
    var that = shape(config);
    that.area = function () {
        return my.l * my.w;
    };
    return that;
};

myShape = shape({
    name: "Unhnown"
});

myRec = rectangle({
    name: "Rectangle",
    length: 4,
    width: 6
});

console.log(myShape.name + " area is " + myShape.area() + " " + myRec.name + " area is " + myRec.area());
Fickle answered 27/10, 2012 at 21:50 Comment(0)
L
884

Primitives are passed by value, and Objects are passed by "copy of a reference".

Specifically, when you pass an object (or array) you are (invisibly) passing a reference to that object, and it is possible to modify the contents of that object, but if you attempt to overwrite the reference it will not affect the copy of the reference held by the caller - i.e. the reference itself is passed by value:

function replace(ref) {
    ref = {};           // this code does _not_ affect the object passed
}

function update(ref) {
    ref.key = 'newvalue';  // this code _does_ affect the _contents_ of the object
}

var a = { key: 'value' };
replace(a);  // a still has its original value - it's unmodfied
update(a);   // the _contents_ of 'a' are changed
Loritalorn answered 27/10, 2012 at 21:51 Comment(18)
I figured this will work too. So my can be defined inside the function. var rectangle = function (config) { var l = config.length || 1; var w = config.width || 1; var that = shape(config); that.area = function () { return l * w; } return that; };Fickle
Though not popular, the behaviour for object is acually named 'call by sharing': en.wikipedia.org/wiki/Call_by_sharing#Call_by_sharingDependable
@IoanAlexandruCucu personally I think "copy of reference" is more intuitive ;-)Loritalorn
@Inverse I rolled back your edit because it completely changed the semantics of it. It's also completely inappropriate to make such substantial changes to such a high voted answer!Loritalorn
ref = {} is the same as ref = new Object() so I wouldn't call it replacing, rather creating a local variable of the same name and local names have priority over global names. In that replace function you can do window.ref to access the global ref which was never actually replaced as it retains it's original value even after you leave that function. While this answer might be correct, I think some explanations of why it works would be helpful.Oberammergau
@Oberammergau you don't appear to understand - the variable ref is a parameter to the replace function, not a global, and parameters and local variables share the same namespace, so writing ref = {} is explicitly replacing its value (albeit with a reference to a new object). window.ref never even comes into it because there are no global variables used here.Loritalorn
Sorry, for some reason I thought global 'a' was also called 'ref'. But if did happen to also be called ref I believe what I wrote is valid. What I think occurs under the covers: 'var a' is basically a pointer to an address. Parameter ref is a new pointer (not located at the same address as a). What 'a' points to is copied to what 'ref' points to. When you then do ref=new Object() 'ref' now points to something else.Oberammergau
If you're going to use the phrase "copy of reference" then you might as well call primitives "copy of value". This why both are actually just "pass by value". Both pass a copy of the value whether that value is a number, bool, string, or reference.Ulland
Pass by copy, pass by reference are the appropriately identifying terms. In this case JavaScript is pass by copy for primitives and pass by reference for Objects. Which is a hot pile of garbage in most cases.Presbyterate
The concept is simple, and should be easy to understand. We are confused because C++ and its offsprings used confusing and illogical terms. Thus we are stuck with "copy of reference". But kudos to Alnitak.Metabolic
I think it's always pass by reference. Doing varname = {...} simply creates a new local var that happens to have the same name as the parameter, and presumably making it impossible after that to access the original parameter due to name overwrite (parameters also being local vars.)Oberammergau
@Oberammergau no, doing just varname = {} does not create a new local variable unless prefixed with var, let, etc. It overwrites the value of that parameter that is in the scope (where that "value" might be a reference to an object), but it does not (by itself) create a "new local variable".Loritalorn
when you say copying a reference, you mean passing by value don't you? the questioner asked about pass by reference and passed by value. And yeah you can pass a reference by value, that's still pass by valueEnshrine
@Enshrine yes, strictly speaking you're correct, a copy of the reference's value is passed (as I say in the last sentence).Loritalorn
@Loritalorn he asks if objects are passed by value. You say references are passed by value, but would you say objects are passed by value? Which is more correct.. To say objects are passed by value, or to say that references are passed by value? Note that references are values (or would you say references are objects?). And perhaps a value can't be passed by reference, though i guess a variable can. So perhaps it's more correct to say objects are passed by xyz, rather than references are? I don't know thoughEnshrine
Correct me if I'm wrong, but it's like a one way street. Meaning that if I pass objX to a function, that function can change a bunch of things. But if I set objX = (some other obj), that reference is not affected. In this case, is there always an unchanged copy of an object in memory since that object was defined? Is the original object ever affected?Marginate
@p32094 if you mean you do objX = { foo } inside the function, then all you've done is change the (reference to the) object that objX is associated with inside the function. The original objX (in the calling code) will remain associated with the original object.Loritalorn
pass by value vs. pass by reference is orthogonal to ECMAScript in general. The behavior is almost identical to that of Python: "Object references are passed by value". Assignments merely create or update namespace aliases to reference values. There doesn't even need to be a separate discussion involving immutables because they declare no internal mutator methods to begin with; the only thing you can do with them is access their values through assignment. Note that "syntactic-sugar" constructors of mutables return a reference to a new object (e.g. [],{}).Ecumenism
B
73

Think of it like this:

Whenever you create an object in ECMAscript, this object is formed in a mystique ECMAscript universal place where no man will ever be able to get. All you get back is a reference to that object in this mystique place.

var obj = { };

Even obj is only a reference to the object (which is located in that special wonderful place) and hence, you can only pass this reference around. Effectively, any piece of code which accesses obj will modify the object which is far, far away.

Babettebabeuf answered 27/10, 2012 at 21:55 Comment(8)
And the reference is itself passed by value, like everything else in JavaScript.Szymanowski
@Szymanowski what is the value of the reference? Is reference a type? I think this word game is just useless.Dynamotor
@Dynamotor I realize that it's frustrating, but every specialized field has specialized terminology. A "reference" means something like what "pointer" means in C or C++ (well C++ has both pointers and references). However in languages like JavaScript or Java for that matter a "value" that is a particular object can only be a reference to the object. So it's not a type, really, it's a characterization of what the value actually is.Szymanowski
@Szymanowski these are language implementation details, the scope and the core concept is the same, so is useless saying it is the value of the reference.Dynamotor
@Dynamotor I will relay that opinion to 2012 me :)Szymanowski
@Szymanowski Classical Stack Overflow moment. The past is catching up with us, for the rest of our natural life.Babettebabeuf
@Babettebabeuf I was struck at the point of this exchange by the somewhat morbid realization that people will be commenting on my answers and comments long after I'm gone from this world.Szymanowski
@Szymanowski and jAndy, past is prologue. (Though Prolog is past.)Devland
V
72

My two cents.... It's irrelevant whether JavaScript passes parameters by reference or value. What really matters is assignment vs. mutation.

I wrote a longer, more detailed explanation in this link.

When you pass anything (whether that be an object or a primitive), all JavaScript does is assign a new variable while inside the function... just like using the equal sign (=).

How that parameter behaves inside the function is exactly the same as it would behave if you just assigned a new variable using the equal sign... Take these simple examples.

var myString = 'Test string 1';

// Assignment - A link to the same place as myString
var sameString = myString;

// If I change sameString, it will not modify myString,
// it just re-assigns it to a whole new string
sameString = 'New string';

console.log(myString); // Logs 'Test string 1';
console.log(sameString); // Logs 'New string';

If I were to pass myString as a parameter to a function, it behaves as if I simply assigned it to a new variable. Now, let's do the same thing, but with a function instead of a simple assignment

function myFunc(sameString) {

  // Reassignment... Again, it will not modify myString
  sameString = 'New string';
}

var myString = 'Test string 1';

// This behaves the same as if we said sameString = myString
myFunc(myString);

console.log(myString); // Again, logs 'Test string 1';

The only reason that you can modify objects when you pass them to a function is because you are not reassigning... Instead, objects can be changed or mutated.... Again, it works the same way.

var myObject = { name: 'Joe'; }

// Assignment - We simply link to the same object
var sameObject = myObject;

// This time, we can mutate it. So a change to myObject affects sameObject and visa versa
myObject.name = 'Jack';
console.log(sameObject.name); // Logs 'Jack'

sameObject.name = 'Jill';
console.log(myObject.name); // Logs 'Jill'

// If we re-assign it, the link is lost
sameObject = { name: 'Howard' };
console.log(myObject.name); // Logs 'Jill'

If I were to pass myObject as a parameter to a function, it behaves as if I simply assigned it to a new variable. Again, the same thing with the exact same behavior but with a function.

function myFunc(sameObject) {
  // We mutate the object, so the myObject gets the change too... just like before.
  sameObject.name = 'Jill';

  // But, if we re-assign it, the link is lost
  sameObject = {
    name: 'Howard'
  };
}

var myObject = {
  name: 'Joe'
};

// This behaves the same as if we said sameObject = myObject;
myFunc(myObject);
console.log(myObject.name); // Logs 'Jill'

Every time you pass a variable to a function, you are "assigning" to whatever the name of the parameter is, just like if you used the equal = sign.

Always remember that the equals sign = means assignment. And passing a parameter to a function also means assignment. They are the same and the two variables are connected in exactly the same way.

The only time that modifying a variable affects a different variable is when the underlying object is mutated.

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.

Vermicelli answered 7/8, 2014 at 7:49 Comment(4)
It's "pass by copy" and "pass by reference" simple as that to convey all the releveant meaning. Do I get "a thing that is it's own thing" or the "thing" is all you care about.Presbyterate
Your assignments(without &), analogy seems to just be an explanation of pass by value isn't it? so why not say so? why says pass by value is irrelevant when you are talking about pass by valueEnshrine
Great explanation Ray!Chitchat
Ray Perea> My two cents.... It's irrelevant whether JavaScript passes parameters by reference or value. What really matters is assignment vs. mutation. - GL_Stephen> It's "pass by copy" and "pass by reference" simple as that to convey all the releveant meaning. Um, you guys realize there's also a performance issue here right? Passing a large array of objects that contain arrays of objects by value is a lot slower than passing it by reference. 😒Tailband
D
41

Function arguments are passed either by-value or by-sharing, but never ever by reference in JavaScript!

Call-by-Value

Primitive types are passed by-value:

var num = 123, str = "foo";

function f(num, str) {
  num += 1;
  str += "bar";
  console.log("inside of f:", num, str);
}

f(num, str);
console.log("outside of f:", num, str);

Reassignments inside a function scope are not visible in the surrounding scope.

This also applies to Strings, which are a composite data type and yet immutable:

var str = "foo";

function f(str) {
  str[0] = "b"; // doesn't work, because strings are immutable
  console.log("inside of f:", str);
}

f(str);
console.log("outside of f:", str);

Call-by-Sharing

Objects, that is to say all types that are not primitives, are passed by-sharing. A variable that holds a reference to an object actually holds merely a copy of this reference. If JavaScript would pursue a call-by-reference evaluation strategy, the variable would hold the original reference. This is the crucial difference between by-sharing and by-reference.

What are the practical consequences of this distinction?

var o = {x: "foo"}, p = {y: 123};

function f(o, p) {
  o.x = "bar"; // Mutation
  p = {x: 456}; // Reassignment
  console.log("o inside of f:", o);
  console.log("p inside of f:", p);
}

f(o, p);

console.log("o outside of f:", o);
console.log("p outside of f:", p);

Mutating means to modify certain properties of an existing Object. The reference copy that a variable is bound to and that refers to this object remains the same. Mutations are thus visible in the caller's scope.

Reassigning means to replace the reference copy bound to a variable. Since it is only a copy, other variables holding a copy of the same reference remain unaffected. Reassignments are thus not visible in the caller's scope like they would be with a call-by-reference evaluation strategy.

Further information on evaluation strategies in ECMAScript.

Dish answered 22/7, 2016 at 19:5 Comment(2)
One the of best & most important answer I've seen about Javascript.Dot
It not only apply to function call, also apply to simple assignment.Dot
E
22

As with C, ultimately, everything is passed by value. Unlike C, you can't actually back up and pass the location of a variable, because it doesn't have pointers, just references.

And the references it has are all to objects, not variables. There are several ways of achieving the same result, but they have to be done by hand, not just adding a keyword at either the call or declaration site.

Exclamatory answered 28/10, 2012 at 1:43 Comment(2)
This is actually the most correct of the answers here. If you ever dig into V8 or the competing engines, this is how function calls are actually implemented.Storied
Under the covers I bet objects are pointers. An object parameter being a newly created pointer that points to the same address as the pointer being passed in.Oberammergau
S
9

JavaScript is pass by value.

For primitives, primitive's value is passed. For Objects, Object's reference "value" is passed.

Example with Object:

var f1 = function(inputObject){
    inputObject.a = 2;
}

var f2 = function(){
    var inputObject = {"a": 1};
    f1(inputObject);
    console.log(inputObject.a);
}

Calling f2 results in printing out "a" value as 2 instead of 1, as the reference is passed and the "a" value in reference is updated.

Example with primitive:

var f1 = function(a){
    a = 2;
}
var f2 = function(){
    var a = 1;
    f1(a);
    console.log(a);
}

Calling f2 results in printing out "a" value as 1.

Subauricular answered 8/3, 2014 at 8:48 Comment(0)
R
5

In practical terms, Alnitak is correct and makes it easy to understand, but ultimately in JavaScript, everything is passed by value.

What is the "value" of an object? It is the object reference.

When you pass in an object, you get a copy of this value (hence the 'copy of a reference' that Alnitak described). If you change this value, you do not change the original object; you are changing your copy of that reference.

Roguery answered 22/11, 2013 at 19:39 Comment(2)
this does not clarify but confuse.Designate
"What is the "value" of an object? It is the object reference." Simple and Perfect!Contrecoup
D
5

In the interest of creating a simple example that uses const...

const myRef = { foo: 'bar' };
const myVal = true;

function passes(r, v) {
  r.foo = 'baz';
  v = false;
}

passes(myRef, myVal);

console.log(myRef, myVal); // Object {foo: "baz"} true
Delores answered 22/8, 2017 at 19:12 Comment(0)
R
3

"Global" JavaScript variables are members of the window object. You could access the reference as a member of the window object.

var v = "initialized";

function byref(ref) {
  window[ref] = "changed by ref";
}

byref((function(){for(r in window){if(window[r]===v){return(r);}}})());
// It could also be called like... byref('v');
console.log(v); // outputs changed by ref

Note, the above example will not work for variables declared within a function.

Rhiamon answered 24/7, 2014 at 21:49 Comment(0)
T
3

Without purisms, I think that the best way to emulate scalar argument by reference in JavaScript is using object, like previous an answer tells.

However, I do a little bit different:

I've made the object assignment inside function call, so one can see the reference parameters near the function call. It increases the source readability.

In function declaration, I put the properties like a comment, for the very same reason: readability.

var r;

funcWithRefScalars(r = {amount:200, message:null} );
console.log(r.amount + " - " + r.message);


function funcWithRefScalars(o) {  // o(amount, message)
  o.amount  *= 1.2;
  o.message = "20% increase";
}

In the above example, null indicates clearly an output reference parameter.

The exit:

240 - 20% Increase

On the client-side, console.log should be replaced by alert.

★ ★ ★

Another method that can be even more readable:

var amount, message;

funcWithRefScalars(amount = [200], message = [null] );
console.log(amount[0] + " - " + message[0]);

function funcWithRefScalars(amount, message) {  // o(amount, message)
   amount[0]  *= 1.2;
   message[0] = "20% increase";
}

Here you don't even need to create new dummy names, like r above.

Truc answered 9/3, 2018 at 17:46 Comment(0)
S
2

I can't see pass-by-reference in the examples where people try to demonstrate such. I only see pass-by-value.

In the case of variables that hold a reference to an object, the reference is the value of those variables, and therefore the reference is passed, which is then pass-by-value.

In a statement like this,

var a = {
  b: "foo",
  c: "bar"
};

the value of the 'a' is not the Object, but the (so far only) reference to it. In other words, the object is not in the variable a - a reference to it is. I think this is something that seems difficult for programmers who are mainly only familiar with JavaScript. But it is easy for people who know also e.g. Java, C#, and C.

Scoff answered 29/1, 2019 at 20:7 Comment(0)
O
2

Objects are always pass by reference and primitives by value. Just keep that parameter at the same address for objects.

Here's some code to illustrate what I mean (try it in a JavaScript sandbox such as https://js.do/).

Unfortunately you can't only retain the address of the parameter; you retain all the original member values as well.

a = { key: 'bevmo' };
testRetain(a);
document.write(' after function ');
document.write(a.key);


function testRetain (b)
{
    document.write(' arg0 is ');
    document.write(arguments[0].key);
    b.key = 'passed by reference';
    var retain = b; // Retaining the original address of the parameter

    // Address of left set to address of right, changes address of parameter
    b = {key: 'vons'}; // Right is a new object with a new address
    document.write(' arg0 is ');
    document.write(arguments[0].key);

    // Now retrieve the original address of the parameter for pass by reference
    b = retain;
    document.write(' arg0 is ');
    document.write(arguments[0].key);
}

Result:

arg0 is bevmo arg0 is vons arg0 is passed by reference after function passed by reference

Oberammergau answered 31/5, 2019 at 1:48 Comment(0)
F
1

Primitives are passed by value. But in case you only need to read the value of a primitve (and value is not known at the time when function is called) you can pass function which retrieves the value at the moment you need it.

function test(value) {
  console.log('retrieve value');
  console.log(value());
}

// call the function like this
var value = 1;
test(() => value);
Fungible answered 24/1, 2019 at 12:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.