DEV Community

Pass by value vs pass by reference in JavaScript

Ashfiquzzaman Sajal on April 30, 2024

Hello there, fellow JavaScript enthusiasts! Today, we're going to dive into the intriguing topic of pass by value vs pass by reference in JavaScrip...
Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

As others have correctly said, JavaScript does not have 'pass by reference'. From MDN (emphasis mine):

Arguments are always passed by value and never passed by reference. This means that if a function reassigns a parameter, the value won't change outside the function. More precisely, object arguments are passed by sharing, which means if the object's properties are mutated, the change will impact the outside of the function

Collapse
 
ashsajal profile image
Ashfiquzzaman Sajal • Edited

Thank you, Jon, for your comment. Obviously, the docs are correct, but it says object arguments are passed by sharing. Here, "passed by sharing" isn't "pass by value" entirely. It's quite similar to "pass by reference". Actually it is an evaluation strategy that is intermediate between call by value and call by reference.

Sell Wikipedia about pass by sharing
Even the example provided after the explanation is isn't satisfying "pass by value".

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

Objects are a reference type (as are arrays and functions). This doesn't mean however that they are passed by reference to a function (if they were, it would be a reference to a reference type). You're confusing two different things.

If JS used pass by reference, you would be able to reassign arguments (i.e. assign an entirely new value or object to them - which would then be seen outside the function). This simply is not possible in JS

Thread Thread
 
ashsajal profile image
Ashfiquzzaman Sajal

Jon, I appreciate your perspective and the documentation you've shared. It has helped clarify my doubt, and I hope it benefits others too.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

JavaScript doesn't have pass-by-reference. All arguments are passed by value. Values being mutable (objects) or immutable (primitives) has nothing to do with this.

Collapse
 
ashsajal profile image
Ashfiquzzaman Sajal

JavaScript does not have traditional pass-by-reference like other languages. However, when dealing with objects (reference types), a reference to the object is passed to the function, allowing changes to the object within the function to affect the original object. This is because JavaScript does not create a copy of the object, but rather passes a reference to the object. This is why changes made to the object inside the function can affect the original object.

Try the code below

function changeName(person) {
    person.name = "John";
    console.log("Inside function:", person);
}

let myPerson = { name: "Jane" };
console.log("Before function call:", myPerson);

changeName(myPerson);
console.log("After function call:", myPerson);

//Output:

//Before function call: { name: 'Jane' }
//Inside function: { name: 'John' }
//After function call: { name: 'John' }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
miketalbot profile image
Mike Talbot ⭐ • Edited

I think the confusion here is in the fact that objects are reference types, when they are made, they are allocated somewhere else in memory and a pointer to that location is stored in a variable.

All arguments are passed by value, so the pointer is copied and sent to the function. It's a copy of the pointer, not a copy of the reference to which the pointer refers. Dereferencing the copied pointer just results in finding the same object as the pointer is an exact copy.

function stuff() {
     const f = 5;
     const o = { f: 5 };
     otherStuff(f, o);
}

function otherStuff(a,b) {
   console.log(a, b.f);
}

Enter fullscreen mode Exit fullscreen mode

In this code we are allocating variables on a stack frame. The stack can contain primitives and primitives include pointers, they don't include objects. A 5 is put on the stack for f and, somewhere else in memory, an object is created {f:5}, the pointer to this object is put in o. Copying o occurs when we call otherStuff but that is just the pointer, not the object.

In JavaScript we don't have structured value types -> no structs -> no copy by value structured data, we only have objects that are allocated on the heap for structured data, these are always reference types.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️
function change_value(value) {
   value = 20
}
let value = 30
change_value(value)
console.log(value) // still 30
Enter fullscreen mode Exit fullscreen mode

JavaScript does not have call by reference.

Collapse
 
oculus42 profile image
Samuel Rouse

JavaScript does not contain pointers, which are the "reference" in pass by reference, but for objects it has the same impact as pass-by-reference... non-primitive values can be mutated.

Apparently this is called pass-by-sharing, though it is not something that I would think to call it.

I think of it as abstracted pass-by-reference. A variable or property which is not a primitive ultimately does have a pointer at a lower level than the language provides. Accessing or mutating the object is accomplished through that hidden reference; we just don't get to see it. If you reassign the parameter, you replace the reference, so the original object from outside the scope is inaccessible.

This essentially follows the description of pass-by-sharing...certain there are certain types that use a reference to share an object.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

There's been lots of attempts at coming up with new words for the combination of call-by-value and reference types, but at the end of the day, those are still, strictly speaking, call-by-value. The value being a reference to some other data that may or may not be mutable.

It's also only half true that JavaScript doesn't have pointers. Pointers are a low-level construct that represents a reference to some data via its memory location as a number, so you can do some degree of arithmetic on them. JavaScript abstracts these internals away, but still gives us references to objects that, internally, use pointers. We can't do arithmetic on these references, but they still can do other things pointers can do, like being passed into a function to be mutated.

As for primitives, since they are all immutable in JavaScript, there isn't really a meaningful distinction between how they are shared. Internally, the VM probably shares at least strings by reference, and might do the same for larger numbers.

If we think of, say, the integer 20 as an instance of some immutable number class, where all operations on it create a new instance, and calling a function with it passes a reference to said number as an argument, then we can still expect it to behave the exact same way as if we think of it as a plain integer that gets copied into whatever memory the function uses.

This is why I think concepts like "pass-by-sharing" are somewhat missing the point: They tell us only about the values we're dealing with and their types, whereas the actual "call-by-reference" / "call-by-value" distinction tells us something about the variables holding the values.

In call-by-reference, the function isn't called on the value itself, but on the variable. If we assign a new primitive value to the function argument, the actual variable outside of it will be changed accordingly. Internally this will likely be implemented by some sort of reference type, but if a subroutine is inlined, then it may well not be. Either way, that's an implementation detail that shouldn't be paid much attention when talking about conceptual language features.

Collapse
 
citronbrick profile image
CitronBrick • Edited

This article is totally wrong. JavaScript is pass by value only.

function addTail(arr) {
    arr = arr.concat('tail');
}

let parts = ['head','chest','stomach'];
addTail(parts);
console.log(parts); // still ['head','chest','stomach'];

function moveDown(p) {
    p = {x: p.x, y: p.y+1};
}

pt = {x:3,y:4};
moveDown(pt);
console.log(pt); // still {x:3,y:4}; only
Enter fullscreen mode Exit fullscreen mode

On the other hand, C++ has both pass by value & pass by reference:


class Point {

public:

    int x,y;

    Point(int _x, int _y) {
        x = _x;
        y = _y;
    }

};

void moveDownCopy(Point pt) {
    pt = Point(pt.x, pt.y + 1);
}

void moveDownRef(Point& pt) { // the ampersand passes a reference
    pt =  Point(pt.x, pt.y + 1);
}



int main() {
    Point p = Point(3,4);
    cout << p.x <<","<<p.y << endl;
    moveDownCopy(p);
    cout << p.x <<","<<p.y <<endl; // still 3,4 only 
    moveDownRef(p);
    cout << p.x <<","<<p.y <<endl; // 3,5
    return 0;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ashsajal profile image
Ashfiquzzaman Sajal • Edited

JavaScript does not have true pass by reference like some other languages. In JavaScript, objects are passed by reference, while primitives are passed by value. This means that when you pass an object to a function, you're passing a reference to that object, but when you pass a primitive (like a number or a string), you're passing a copy of its value.

You can try the code below that I included in the article before.

function changeName(person) {
    person.name = "John";
    console.log("Inside function:", person);
}

let myPerson = { name: "Jane" };
console.log("Before function call:", myPerson);

changeName(myPerson);
console.log("After function call:", myPerson);

//Output:

//Before function call: { name: 'Jane' }
//Inside function: { name: 'John' }
//After function call: { name: 'John' }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
efpage profile image
Eckehard • Edited

Sorry, but you are confusing people. It is really important to understand exactly, how Javascript objects work.

let a = { name: 'Jane'}
let b=a
b.name = 'John'
Enter fullscreen mode Exit fullscreen mode

Did you kill 'Jane' or not??? You should know!

Objects are references, if you use them as a parameter, you just pass a copy of that reference. In fact, it is not easy to make a deep copy in JS. If objects would be passed "by reference", this schould work (which does not).

function changeName(person) {
    person = {name: "John"};
    console.log("Inside function:", person);
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
ashsajal profile image
Ashfiquzzaman Sajal

Thank you, Eckehard, for your input. Would you mind elaborating further?

Thread Thread
 
efpage profile image
Eckehard • Edited

Look here for details.

Collapse
 
ashsajal profile image
Ashfiquzzaman Sajal

Did the article clarify the doubt about, pass by value vs pass by referrence?

Collapse
 
baltasarq profile image
Baltasar García Perez-Schofield • Edited

On the surface, you can say that primitives are "passed by value", and objects are "passed by reference". Actually, JavaScript only passes by value, as Java does.

Probably the actual implementation explains how: JavaScript passes the reference to the object to functions (by value). When the value is a primitive, however, the value is stored in the reference itself. This explains the behaviour which can be, at first, strange.

Collapse
 
ashsajal profile image
Ashfiquzzaman Sajal

Thanks for you comment Perez. In JavaScript, everything is passed by value, but for objects, it's the reference to the object that's passed. Primitives get their values copied directly, while objects get their references copied. This can lead to some surprises if not handled carefully.

Collapse
 
abhijivani3001 profile image
Abhi Jivani • Edited

How can i do pass by reference for primitive data types??

Collapse
 
ashsajal profile image
Ashfiquzzaman Sajal

It's not possible. But you can wrap the primitive data in an object which is unnecessary I guess. Thanks for your comment.