DEV Community

Discussion on: A "Gotcha" of JavaScript's Pass-by-Reference

Collapse
 
functional_js profile image
Functional Javascript • Edited

Again, I am in 100% agreement Adam

There are three stack allocation cases (Javascript supports the first two only):

pass value:

allocate a value type
(a value type = primitive type, eg. number, boolean, string, etc)
the developer's data (value) is IN the stack frame. There is no reference to the heap.
note: assume this includes strings because they have "value semantics", so their allocations behave like a primitive.
Applies to either a variable assignment or function invocation

pass reference:

allocate a reference type
(a reference type = heap objects, eg. array, object, function, etc)
Just like pass by value, a new stack frame is allocated, but the stack frame does not contain the developer's data (value), but only a reference to it on the heap. Therefore a REFERENCE was passed, no data (value) was passed, as the data continues to unknowingly sit on the heap untouched and unaffected by the stack allocation.
Summary: A reference is copied; the end value itself is not copied.
Applies to either a variable assignment or function invocation

pass a reference of reference

Just like the previous two, a new stack frame is allocated, but the newly created stack frame does not point to the heap, but to the stack frame below it which thus points to the data on the heap (one extra level of indirection)
note: Never use this. Using this is like using the Unsafe keyword in C#. You'd only use this for things like interop with DCOM. It would be an extremely, advanced, bizarre case. That is why there is a specialized keyword that must be placed on both the caller and callee to even be able to do it (a double red flag). It cannot be used by default, nonexplicitly, or accidently, for it's a massive antipattern if used outside of it's extreme, highly-specific edge case.
This is why it doesn't exist in Javascript. There'd be no need for it, and would only create a crap ton more load of bugs.
Applies to function invocation only

Collapse
 
bytebodger profile image
Adam Nathaniel Davis

I didn't even realize that there is such a thing as "pass a reference by reference" - in any language. Very interesting. At some point, when I'm done writing code for the day but my brain hasn't yet completely shut down, I'll probably read up on that - just as an interesting trivia point.

Thanks!

Collapse
 
functional_js profile image
Functional Javascript • Edited

Here's an example from the C# docs (though massively naive and antipattern-ish, because one would never have to do this). Notice two ref keywords must be used, in the caller and callee.
Btw, I've coded in C# for years and I've never used it, and never seen it used. It really shouldn't exist.

class PassingRefByRef
{
    static void Change(ref int[] pArray)
    {
        // Both of the following changes will affect the original variables:
        pArray[0] = 888;
        pArray = new int[5] {-3, -1, -2, -3, -4};
        System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
    }

    static void Main()
    {
        int[] arr = {1, 4, 5};
        System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);

        Change(ref arr);
        System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
    }
}
/* Output:
    Inside Main, before calling the method, the first element is: 1
    Inside the method, the first element is: -3
    Inside Main, after calling the method, the first element is: -3
*/

Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
netional profile image
Netional

I recently came across a Typescript use case (admittedly seldom happens) for reference to the reference in which I wanted to have a function that disposes of passed in class members and set them to undefined. This is not possible in JS or Typescript as far as I can see.

private DisposeOrbitalControls(orbitControls: OrbitControls | undefined): void {
    if (orbitControls !== undefined) {
      orbitControls.dispose();
      orbitControls = undefined
    }
}

this.DisposeOrbitalControls(this.orbitControlsOrtho)
this.DisposeOrbitalControls(this.orbitControlsPerspective)
//this.orbitControlsOrtho and this.orbitControlsPerspective are not set to undefined
Enter fullscreen mode Exit fullscreen mode

Some comments have been hidden by the post's author - find out more