DEV Community

Discussion on: Pass by value vs pass by reference in JavaScript

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
 
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
 
ashsajal profile image
Xaman

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.