DEV Community

loading...

Discussion on: Passed By Reference Vs. Value In Javascript

Collapse
sleeplessbyte profile image
Derk-Jan Karrenbeld

Whilst this is a great post and the overal information is correct, the pedantic semantic details are not. It all comes down to what it means to say something is "pass by x", and not what people who ask this question usually meant. I will explain why, but first

JavaScript is always pass by value

You're not the first one that tries to make a distinction between primitives and objects, and I understand why people do. However, there is none.

The term pass by reference and pass by value only applies to function calls and their arguments. Consider the following (JS syntax) code:

function reference_assignment(myRefMaybe) {
  myRefMaybe = { key: 42 }
}

var primitiveValue= 1
var someObject= { is: 'changed?' }

reference_assignment(primitiveValue)
primitiveValue
// => 1

reference_assignment(someObject)
// => { is: 'changed?' }
Enter fullscreen mode Exit fullscreen mode

The fact is that someObject has not been changed, because it was not a reference to someObject's content that has been passed. A language that does support pass by reference is PHP, but it requires special syntax to change from the default of passing by value:

function change_reference_value(&$actually_a_reference)
{
    $actually_a_reference = $actually_a_reference + 1;
}


$value = 41;
change_reference_value($value);
// => $value equals 42
Enter fullscreen mode Exit fullscreen mode

I tried to keep the same sort of semantic as the JS code.

As you can see, the PHP example actually changes the value the input argument refers to.

What's wrong with call-by-value?

The term call-by-value is problematic. In JavaScript the value that is passed is a reference. That means that, indeed, that the reference to the boxed primitive is copied, and therefore changing a primitive inside a function doesn't affect the primitive on the outside. That also means that, indeed, the reference to a reference type, such as an array or object, is copied and passed as the value. This results in the exact behaviour that is described.

The lesser used and known term that was coined is Call by sharing which applies to Ruby, JavaScript, Python, Java and so forth. It implies that all values are object, all values are boxed, and they copy a reference when they pass it as value.

Here is another example to demonstrate this:

function appendOne(list) {
  list.push(1)
}

function replaceWithOne(list) {
  list = []
}

const first = []
const second = []

appendOne(first)
first
// => [1]

replaceWithOne(second)
second
// => []
Enter fullscreen mode Exit fullscreen mode

In the first example it outputs [1], because the push method modifies the object on which it is called. This propagates because the list argument still refers to the original object first (its reference was copied and passed as a value).

In the second example it outputs [] because the re-assignment doesn't propagate to the caller. In the end it is not re-assigning the original reference but only a copy.


In short: It's always pass by value, but the value of the variable is a reference. All primitive-methods return a new value and thus one can not modify it, all objects and arrays can have methods that modified their value, and thus one can modify it.

P.S. C actually is also always pass by value / call by value, but it allows you to pass a pointer which can simulate pass by reference:

void modifyParameters(int value, int* pointerA, int* pointerB) {
    // passed by value: only the local parameter is modified
    value = 42;

     // passed by value or "reference", check call site to determine which
    *pointerA = 42;

    // passed by value or "reference", check call site to determine which
    *pointerB = 42;
}

int main() {
    int first = 1;
    int second = 2;
    int random = 100;
    int* third = &random;

    // "first" is passed by value, which is the default
    // "second" is passed by reference by creating a pointer,
    //         the pointer is passed by value, but it is followed when
    //         using *pointerA, and thus this is like passing a reference.
    // "third" is passed by value. However, it's a pointer and that pointer
    //         is followed when using *pointerB, and thus this is like
    //         passing a reference.
    modifyParameters(first, &second, third);

    // "first" is still 1
    // "second" is now 42
    // "random" is now 42
    // "third" is still a pointer to "random" (unchanged)
    return 0;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
powerc9000 profile image
Clay Murray

Thank you! I see the misconception about pass by reference / value a lot.

Collapse
cjwd profile image
Chinara James • Edited

This comment should probably be it's own blog post.

Collapse
sleeplessbyte profile image
Derk-Jan Karrenbeld

I will!

Thread Thread
steelvoltage profile image
Brian Barbour Author • Edited

Yeah I do apologize for potentially spreading misinformation. I was just recapping things I learned in an Advanced Javascript course.

Link me to your post when you make it, and I'll add it at the bottom of this one as a "However, this is more nuanced than it seems on the surface, for a deeper dive check out this article."

Thread Thread
sleeplessbyte profile image
Derk-Jan Karrenbeld

Don't worry! Keep recapping. Like I said, it holds value :)

I'll reply here with the link once it's up!

Thread Thread
sleeplessbyte profile image
Derk-Jan Karrenbeld
Collapse
steelvoltage profile image
Brian Barbour Author

Wow, the resources I used to learn Javascript never mentioned this at all, thanks for sharing! Very illuminating.

Collapse
sleeplessbyte profile image
Derk-Jan Karrenbeld

If you try to look this up, most resources will actually mention it incorrectly and even hostile toxic discussion against people who say exactly what I say :(. I only know what I know because I spend quite some time in this implementation in V8 and MRI ruby (and because I had some of this in university).

It also doesn't help that it's really mostly semantics and pedantic, but nomenclature can definitely confusing. I hope you can turn my explanation in a few sentences for the #beginners ❤

Thread Thread
baso53 profile image
Sebastijan Grabar

This exactly. Almost no resource explains this correctly and I think that this is one of the harder things to explain to beginners, but also one of the most important. Obviously, someone who had some C/C++ education would be a bit better at understanding the reasons why this happens, but even those lessons are usually not very good at explaining the differences in detail.

Your explanation on the other hand is pretty good. And good job! :)

Thread Thread
sleeplessbyte profile image
Derk-Jan Karrenbeld • Edited

I guess I'll write an article.

That said, I completely understand where Brian is coming from. It's moreso the lack of writing than that it's super hard. I think Brian did a stellar job giving us the difference of passing an object/array vs primitive, in the practical sense, which is in the end the only thing the beginner will really use.