DEV Community

wlytle
wlytle

Posted on

Passing variables and objects in Javascript: Reference compared to Values

Motivation

I'm applying and interviewing for jobs right now and consequently brushing up on algorithms and data structures. This has led me to a lot of tinkering with recursion and backtracking. I'm a kinesthetic learner and keeping track of what's going on deep in a recursion stack makes my brain tired - so practice! This is NOT a blog about recursion and backtracking, although one of those may be here soon (In the meantime here is a pretty good article on the subject.

All this practice has brought my attention to a Javascript feature (quirk) that I often forget about in these situations - Javascript's passing of values or references depending on the data type.

Reference Vs. Value

When passing a variable that points to an object a reference to that object gets passed. When passing a variable that points to a number, boolean, string, or undefined the value of the variable is passed. Practically this means assigning multiple variables to an object will allow all of those variables to access the same object. This is not true with values. Quick example:

let x = "Cheddar";
let y = x;
y = "Manchego"
console.log(x) //"Cheddar" 
console.log(y) //"Manchego"

let x = ["Cheddar"];
ley y = x;
y.push("Manchego");
console.log(x); //["Cheddar", "Manchego"]
console.log(y); //["Cheddar", "Manchego"]
Enter fullscreen mode Exit fullscreen mode

We can get around this by using the spread operator:

let x = ["Cheddar"];
ley y = [...x];
y.push("Manchego");
console.log(x); //["Cheddar"]
console.log(y); //["Cheddar", "Manchego"]
Enter fullscreen mode Exit fullscreen mode

Importance for Recursion

Okay, that's all well and good but what does this have to do with recursion? Well, to be perfectly honest, not much, but for me, it keeps coming up when refactoring iteration to recursion or visa-versa.

Let's take a look at the quintessential recursion example: Fibonacci (More info on the Fibonacci sequence available on the always helpful Wikipedia).

Here's a quick function to return the nth term in the Fibonacci sequence:

function fibonacci(n) {
  const dict = {};
  return calcFib(n, dict);
}

function calcFib(n, dict) {
  if (n === 1 || n === 2) {
    return 1;
  }
  if (dict[n]) return dict[n];
  result = calcFib(n - 1, dict) + calcFib(n - 2, dict);
  dict[n] = result;
  return result;
}
Enter fullscreen mode Exit fullscreen mode

Notice that at every return we have to return the result. If we had chosen to make result an argument of calcFib, we would still need to return the result of the calculation. This is because when we pass down result to another instance of calcFib it is just the value result points to not the result we will eventually return. Another way to look at this is through the lens of our memoization dictionary, dict. We never return this value yet it remains updated through all instances of calcFib. This happens because dict is an object and so we are updating a reference to the location of dict in memory, not just the values contained in dict.

Let's look at a non-recursive version to see if we can clear this up. Here is an iterative function to return an array of the first n terms of the Fibonacci sequence.

function calcFib(current, previous, result) {
  result.push(current + previous);
}

function fibonacci(n) {
  let result = [];
  //base cases
  if (n === 1) return result.push(1);
  if (n >= 2) {
    result.push(1);
    result.push(1);
  }

  for (let i = 1; i < n - 1; i++) {
    calcFib(result[i], result[i - 1], result);
  }
  return result;
}
Enter fullscreen mode Exit fullscreen mode

Notice that in calcFib we don't return anything! We can get away with this because we are updating an array (which in Javascript is a type of object) and that means we are passing calcFib a reference to the result array. When we add another value of the sequence to result we are always updating the same object in memory.

Final thoughts

The 5-cent takeaway here: in Javascript objects are passed by reference, meaning they always point to the same object in memory even if being passed to another function with a different scope. Everything else is passed by value, so if you are entering another scope and you want an updated value back make sure to return it!

Thanks for reading and hope this saves someone a bit of debug time.

Top comments (1)

Collapse
 
jwrunge profile image
Jacob W Runge

This can be a powerful tool if you keep it in mind, or an unsolvable riddle if you don't. It makes me wish JavaScript just explicitly used pointers and passes-by-reference. It's all happening under the hood anyway; just give us some transparency and finer-grained control!