Troll Hunting 101: JavaScript Passes Objects by Reference

Adam Nathaniel Davis - Aug 22 '20 - - Dev Community

Sometimes I fall into the trap of thinking that I've seen it all. I may not know every technology. But I'm usually familiar with all the major movements-and-mindsets that pulsate throughout the programming communities.

So I was quite shocked recently when Dev.to introduced me to an entirely different species of troll. One I'd never encountered in my quarter century of programming experience.

I'm talking about the pass-by-reference troll.


Alt Text

How I Discovered the Pass-by-Reference Troll Species

I was writing an article, right here on this site, about cloning objects in JavaScript. (You can read it here: https://dev.to/bytebodger/cloning-objects-arrays-in-react-5475) I gave the following example:

const phantomMenace = { master: 'palpatine', apprentice: 'maul' };
const attackOfTheClones = phantomMenace;
attackOfTheClones.apprentice = 'dooku';
console.log(phantomMenace.apprentice);  // dooku(!)
Enter fullscreen mode Exit fullscreen mode

Before the code example, I made this statement:

In most programming languages, objects (and their nephews, arrays) are passed by reference.


To be honest, I never really gave any more thought to it as I wrote the rest of the article. To me, saying that "in most programming languages, objects are passed by reference" is akin to saying that "in most lakes, the water is wet." This wasn't some radical new idea I was putting into the blogosphere to challenge traditional mores. It was a basic statement of Dev 101.

Then a particular commenter latched onto my post, starting with his contention that almost no languages feature pass-by-reference. And that JavaScript has no pass-by-reference. And that I apparently have no idea how JavaScript - or any other language works. And the commenter was adamant.

To be clear, the commenter wasn't particularly accurate. Nor persuasive. First, they started sending me examples in Java - as though Java and JavaScript are interchangeable. Then they started telling me that code I put in my examples didn't do what I said it would do (it absolutely did - and I had the StackBlitz's to prove it). Then they just kept diving into circular arguments - even going so far as to put up their own code examples that only served to illustrate my point.

Nevertheless, this particular commenter was so vehement that it actually led me to question my premises. Had I been misunderstanding a critical detail for most of my professional life? After all, I want to be open-minded. And anything's possible...

So I reached out to a friend of mine. He's about 20 years younger than me (so he has none of that old-guy stink in his thought patterns). And he's one of these guys who thinks in code. He's highly entertained by esoteric questions of coding theory. He's basically a prodigy. And quite frankly, he's a far better programmer than I. So I shot him this basic question:

ME: Hey, sorry for the silly, basic, theoretical question, but I gotta ask this as part of a little personal experiment: In JavaScript, objects are passed by... value? By reference? By... something else?? It's not a trick question. What is your knee-jerk answer??


Within a minute or two, he replied:

PRODIGY FRIEND: By reference


A few minutes later, he elaborated with this:

PRODIGY FRIEND: Pass an object into a function and then change someObject.someProperty and the original object in the original scope will also change. Was someone arguing this point with you? LOL




Alt Text

Troll Sightings in the Wild

Initially, I brushed off this "rogue commenter". I'd never heard anyone else go so bat-shit crazy about such a basic concept in programming. And then... I started seeing more of them. Here. On Dev.to. (And, curiously enough, only on Dev.to - don't know exactly what that means.)

And they're jerks. I'm sorry to put it in such confrontational terms. But it's true. They feel compelled to jump on any post they can where someone dares to claim that JavaScript objects are passed by reference. And many of their responses are pedantic bullying, where they expect you to prove that they're wrong.

At first, I had a really hard time even describing some of the ridiculous comments I saw on this site with regard to pass-by-reference. But then it hit me.

You know what the JavaScript Pass-By-Reference Trolls are just like???


Alt Text

Knowledge is the Enemy

Do pass-by-reference trolls and flat-earthers have their own dating app? Do they send each other secret admirer letters? Are they the same people???

If you've ever tried to argue with a flat-earther, you know that it's an exercise in futility. They won't listen to anything you say. They will unrepentantly use all manner of logical fallacies. They don't mind mashing up examples from any scientific discipline to "further" their objectives.

One day, you go to sleep content in the knowledge that some ideas have been so universally proven that they cannot be refuted as scientific fact. The next day, you have some belligerent flat-earther moron sitting at your table telling you that you must prove to him every aspect of your ridiculous and specious understanding (the same "understanding" that's upheld by every scientist and educated individual on the face of the planet).

It's quite the same with JavaScript's pass-by-reference trolls. Once they hear you commit the Cardinal Sin of discussing JavaScript's pass-by-reference, they will pounce.


Alt Text

An Epic Waste of Time

When I was first trying to treat these people seriously, I tried to make the case as dead-simple as possible:

// Are you telling me that THIS:
const phantomMenace = 'first movie';
let attackOfTheClones = phantomMenace;
attackOfTheClones = 'second movie';
console.log(phantomMenace); // first movie

// Is functionally no different than THIS???
const phantomMenace = { master: 'palpatine', apprentice: 'maul' };
const attackOfTheClones = phantomMenace;
attackOfTheClones.apprentice = 'dooku';
console.log(phantomMenace.apprentice);  // dooku(!)
Enter fullscreen mode Exit fullscreen mode

In both examples, we have an original variable. A second variable was created, initialized by the first variable. The second variable was then mutated. And... here's where the examples are unique: In the first example, the original variable is unchanged. In the second example, the original variable absolutely is changed.

The difference is that, in the first example, the values are primitives. Primitives are always passed by value. Another way to think of "passed by value" is that the value is passed as a fresh copy of the original.

But in the second example, the values are objects. Objects are always passed by reference. Another way to think of "passed by reference" is that the value passed is a pointer to the original value. You know what's another name for "pointer"??? Reference

I don't know how I could make it any clearer than that. And yet, I gave this exact example to a pass-by-reference troll and asked him, "Are you telling me that the values in both of these examples are passed by value??" And he said, "Yes."


Alt Text

Rules Lawyers

Although it's honestly difficult to follow most of their dogmatic rantings, one thing is clear: Many of them revel in being rules lawyers. They don't seem to care so much about how code works (like: in the example shown above). They care about pedantic details about how code is defined. In stodgy spec documents.

One example of this is when they say things like:

Please show me in the ECMAScript spec where it says...


Nope. Uh-uh. Not even going there. My working code sample is above. I don't care about the exact terminology that someone chose to use when writing a spec doc as part of a bureaucratic open-source committee.

I don't doubt that the words "pass by reference" might not actually exist in the ECMAScript spec. That in no way overrides the empirical fact that I can illustrate objects being passed by reference in the extremely simple example above.

I don't care so much about the exact verbiage chosen when people decided to write out a lengthy spec. I care about how the code actually works.

I don't know if the Java spec actually uses the words "object-oriented language". Maybe it does. Maybe it doesn't. I honestly couldn't care less. Even if those words exist nowhere in the Java spec, the simple fact is that Java is an object-oriented language.

Similarly, I really don't care if the words "pass by reference" exist in the JavaScript spec. JavaScript does pass objects by reference.


Alt Text

What is the Meaning of "is"??

The pedantics don't stop with snobbish references to the ECMAScript spec. Some of the trolls wanna challenge the meaning of the word "value". They typically say something like this:

When you set one variable equal to an object, it's still set by value. It's just that the value is a reference to another object.


Yes. I've heard/read that exact effery. This is not some sad joke. It's a banal reality.

Under this mindset, there is no such thing, in the entire programming world - or even in any other part of the physical world - as a "reference". Because, under this thinking, every "reference" is, in itself, a type of "value" (that holds... a reference).

Now I'm sure that Plato and Socrates would love to toss that distinction around for a few decades while they work out the difference between "a reference" versus "a value - that holds a reference".

But I don't have the time to wait for dead philosophers to figure out whether trees, falling in the woods, actually make a sound if no one is there to hear it. I have to write code. And meet deadlines. And explain esoteric coding concepts to junior developers.

When I'm trying to show a new developer the difference between the two examples shown above, you can sure-as-hell bet that I don't tell them, "You see... It turns out that all of these variables are passed by value! And you'll just have to pray to some ancient god to determine why the behavior is so different."


Alt Text

The Pedantry of "Passing"

The pedantry doesn't stop at the definition of "value". The trolls also wanna argue about "pass". Under this strain of trollishness, the argument goes:

In your examples shown above, there is no "passing" taking place - because there are no functions.


OMFG.

Despite what you may surmise from these blogs, I actually speaka de English reals good. And I know what "pass" means.

Yes, I thoroughly understand that, in programming, "passing" often refers to the idea that we pass arguments into functions. But when you do this:

const firstVariable = 'foo';
const secondVariable = firstVariable;
Enter fullscreen mode Exit fullscreen mode

There is nothing logically incorrect in saying that we have passed the value of firstVariable into the initial state of secondVariable. If that's not your preferred verbiage, then fine - whatever. But that doesn't mean it's wrong to say that the value of firstVariable was passed into secondVariable.

But let's set aside the Merriam-Webster definitions of "passing" for a moment. Because even if we accept that pass-by-reference and pass-by-value can only apply when we are passing values into a function, JavaScript STILL passes by reference!

Wanna argue with me, trolls?? Here's the oh-so-simple example:

const myObject = {
  one: 'uno',
  two: 'dos',
};
const myString = 'marco';

const myFunction = (theObject, theString) => {
  theObject.one = 'einz';
  theString = 'polo';
}

myFunction(myObject, myString);
console.log('myObject', myObject); // {one: 'einz', two: 'dos'}
console.log('myString', myString); // 'marco'
Enter fullscreen mode Exit fullscreen mode

Inside myFunction(), when theObject is mutated, the change is reflected back in myObject. Wanna know why??

Because JavaScript passes objects by reference.

Also inside myFunction(), we mutated theString. But that change was not reflected back in myString. Wanna know why??

Because JavaScript passes primitives by value.


Alt Text

More Than Terminology

It's tempting to paint this as just a simple mismatch in terms. Nothing more than a misunderstanding, if you will.

We could say that JavaScript objects are "copied as pointers". And that JavaScript primitives are "copied as literals". For some minds, that might be a clearer definition. Depending upon your chosen dogma, it might sit easier on your mind.

But... no. That's BS. Sorry (not sorry), but it just is.

You see, if you wanna argue that a "reference" is just "a value that holds a reference" - then you're gonna argue the same thing about a "pointer". To be clearer, if you wanna make this kinda argument, then... you just enjoy arguing.

And if you have a problem with "pass" because you think it can only possibly be applied to functions - well then... you just don't have a solid grasp of the English language. I'm sure that sounds snarky and combative - but it's absolutely true.


Alt Text

The Power of Words

This rant may lead you to believe that I don't care at all about technical definitions or that I play fast-and-loose with jargon. But nothing could be farther from the truth.

In all areas of life, but especially in tech, I fully understand that words can have extremely specific meanings. And that botching those meanings can have real world consequences.

But I also understand that words portray concepts. If we focus on the words for the sake of arguing about specific words, then we've missed the entire point. Language only has meaning in context.

So when you wanna get on your rules-lawyering high horse about passing by reference, or passing by value, you need to keep in mind one extremely basic - and tactical - fact. It would seem, on the surface, that these two examples should behave in the exact same way:

// Are you gonna telling me that THIS:
const phantomMenace = 'first movie';
let attackOfTheClones = phantomMenace;
attackOfTheClones = 'second movie';
console.log(phantomMenace); // first movie

// Is functionally no different than THIS???
const phantomMenace = { master: 'palpatine', apprentice: 'maul' };
const attackOfTheClones = phantomMenace;
attackOfTheClones.apprentice = 'dooku';
console.log(phantomMenace.apprentice);  // dooku(!)
Enter fullscreen mode Exit fullscreen mode

But of course... they do not behave in the same way. In the first example, the changes to the mutated object are reflected back on the source object. In the second example, the changes to the mutated string are not reflected back on the source string. Why???

Because primitives in JavaScript are passed by value. And objects in JavaScript are passed by reference.


If you think that the examples above are operating under the exact same principle - that all the variables are passed by value - well... good luck to you. Enjoy yelling at people over pedantic details for the rest of your life - details that only you, with your heroic knowledge, can possibly understand.

[FINAL NOTE: This will be the 53rd article I've published on Dev.to. I've always taken pride in answering most of the comments that are left on my blogs. For this particular article, I won't be responding - to anything. I've learned from reading around on this subject that the "there is no pass by reference!" crowd can be, quite honestly, jerk-wads. (Technical term.) And I have no desire to engage with the flat-earthers for another round of pigeon chess.]

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player