I don't mean to troll but I can understand why a lot of people are adamant about the terminology. In languages like C++ or C#, you can actually pass a reference not just to the object (the value), but rather to the object's holder (the variable).
So I think a lot of people think like this
Pass-by-value: Pass the value of this variable
Pass-by-reference: Pass a reference of this variable
Since most languages agree that "Pass-by-reference" is sort of dangerous, they don't have it. Which can lead to many people re-purposing the term "pass-by-reference", changing the meaning from "pass a reference of the variable" to "this variable holds a reference which is being passed".Since passing a reference of the variable isn't even possible in JS, so why have a term for that anyway?
I think a good litmus test for whether a language can pass the reference of the variable would be whether you can write a swap function in that language.
Here's a sample code in C++
You can do something similar in C# (with some changes), but it isn't possible in JS or Java, without wrapping a variables inside some type of container, and then passing that container.
So in JS or Java, the references to variables can never be passed, rather variables can hold the value of a reference, and that value can get passed.
I'll admit that maybe I'm the one with the massive mental block on this one. Maybe I'm the one who's fighting against the simple solution of the Monty Hall Problem. But every single time someone tries to explain to me why JS has no pass-by-reference, they either ignore the simple, tactical, repeatable examples I've already provided, or they say/show something that actually only furthers my case.
In my first example, I show a basic process by which we 1) initialize two variables, 2) pass those variables into new variables, 3) mutate the new variables, and 4) output the values of the original variables. In the example, the first original variable (the primitive value) is unchanged - because it's passed by value. The second original variable is changed - because it's passed by reference. It's already shown above, but here's a stripped down version of it:
It's obvious that something very different happens to the two original variables - mostImportantNumber and spanishNumbers.
We never performed any mutation directly on mostImportantNumber and, understandably, the value of mostImportantNumber remains constant. We never performed any mutation directly on spanishNumbers - yet the value of spanishNumbersis updated.
I don't know how I can make it any clearer than this. It's demonstrably, provably obvious that the newly-created variable germanNumbers maintains some kind of "link" back to its initializing variable spanishNumbers. It's demonstrable and provable because, when we update the members of germanNumbers, the change is reflected back on spanishNumbers.
As long as I've been programming, this "link" has been called a "reference". If you (or anyone else) wants to tell me that this "link" is not a "reference", then that's fine - but that leads me to your question:
Since passing a reference of the variable isn't even possible in JS, so why have a term for that anyway?
Because, in JS (and many other languages), the behavior of a passed primitive is demonstrably different than the behavior of a passed object.
It's really that simple. Why would we keep calling a "kick" a "throw" if it's demonstrably obvious that they're two different behaviors, and two different things are happening in those actions??? And why would we keep calling JS objects that have been passed "pass-by-value" when it's demonstrably obvious that they behave entirely differently from primitives that have been passed by value???
Because, in JS (and many other languages), the behavior of a passed primitive is demonstrably different than the behavior of a passed object.
Actually there's no practical difference between how JS passes a primitive value or an object. I'm sorry if I came off wrong. I was just pointing out where a lot of people who were arguing about it where coming from. As for the example you provided.
// initialize variablesletmostImportantNumber=3.14;letspanishNumbers={one:'uno',two:'dos',three:'tres'};// pass variables letanswerToEverything=mostImportantNumber;letgermanNumbers=spanishNumbers;// mutate variables answerToEverything=42;// This is an assignment, not a mutationgermanNumbers={one:'einz'}// This would be the equivalent operation for an object// output original variablesconsole.log(mostImportantNumber);// 3.14console.log(spanishNumbers);// { one: 'uno', two: 'dos', three: 'tres' } <-- Unchanged
The JS runtime has no reason to treat a primitive assignment differently to an object assignment. In fact, you can even try to mutate a primitive just like an object, and JS will allow you to do that as well. It just throws away any mutations you make, which is why it appears that you are operating on another copy of the primitive. But in reality both variables point to the same primitive as well.
answerToEverything.one=42;// Perfectly valid, it just doesn't mutate 'answerToEverything', since primitives are immutable by defaultgermanNumbers.one='einz';// Since objects are mutable by default, this mutates 'germanNumbers'
In fact, if you freeze the object, you can make an object immutable as well, and essentially get the same behavior between objects and primitives, which demonstrates that you don't need to copy anything to make an object behave like a primitive.
// initialize variablesletmostImportantNumber=3.14;letspanishNumbers={one:'uno',two:'dos',three:'tres'};spanishNumbers=Object.freeze(spanishNumbers);// We freeze the object i.e. make it immutable like a primitive// pass variables letanswerToEverything=mostImportantNumber;letgermanNumbers=spanishNumbers;// mutate variables answerToEverything=42;germanNumbers.one='einz';// This mutation doesn't do anything, since the object is 'frozen' i.e. immutable// output original variablesconsole.log(mostImportantNumber);// 3.14console.log(spanishNumbers);// { one: 'uno', two: 'dos', three: 'tres' } <-- Unchanged
I suppose you could say that primitives are like objects that are just frozen by default. While this is technically not true, unless you attempt any operation specific to a primitive (such as addition,subtraction,etc), for the JS Runtime, they are treated exactly in the same way (such as when assigning them to variables or passing them to functions)
I've been noticing that a lot of people who seem entrenched in the idea that "JS has no pass-by-reference" seem to give me examples from C/C++. So I'm honestly wondering if this is just an artifact of people trained in a particular paradigm then (naturally) clinging to that paradigm even when they move outside their original area??
I was curious about how C++ would define pass-by-reference. The IBM Knowledge Center is one of the first pages that comes up: ibm.com/support/knowledgecenter/SS...
It has some very... interesting detail. It starts off with this:
Pass-by-reference means to pass the reference of an argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the argument by using its reference passed in.
In this JS example, the calling function passes two arguments as parameters to the called function. The called function modifies the value of those arguments. But the change is only reflected on one of those arguments - the object. Why?? Because the object is passed by reference.
The IBM Knowledge Center definition goes on to state that:
The difference between pass-by-reference and pass-by-value is that modifications made to arguments passed in by reference in the called function have effect in the calling function, whereas modifications made to arguments passed in by value in the called function can not affect the calling function. Use pass-by-reference if you want to modify the argument value in the calling function. Otherwise, use pass-by-value to pass arguments.
So look at exactly what happened in my simple JS example. A modification made to an argument passed in by reference in the called function (someObject) has effect in the calling function. Whereas a modification made to an argument passed in by value in the called function (somePrimitive) does not affect the calling function.
There it is, defined by IBM with regard to C++. Even by that definition, JS is passing the object by reference.
If C++ prevents reassignment of a reference to another reference through strong typing enforcement, (been decades since I programmed in C++ so those memories are lost, but a brief survey of the web would indicate that references are static once created in C++.) Maybe that difference is what is confusing to C++ folks about JS reference passing and maybe would get at the heart of why they are stuck on the idea that JS doesn't pass by reference. The difference is in strong versus loose typing not passing by reference. Does that make any sense?
If you CAN destroy a reference and reassign it to another object in C++ then an example that shows it's the same would be equally enlightening.
I don't mean to troll but I can understand why a lot of people are adamant about the terminology. In languages like C++ or C#, you can actually pass a reference not just to the object (the value), but rather to the object's holder (the variable).
So I think a lot of people think like this
Since most languages agree that "Pass-by-reference" is sort of dangerous, they don't have it. Which can lead to many people re-purposing the term "pass-by-reference", changing the meaning from "pass a reference of the variable" to "this variable holds a reference which is being passed".Since passing a reference of the variable isn't even possible in JS, so why have a term for that anyway?
I think a good litmus test for whether a language can pass the reference of the variable would be whether you can write a
swap
function in that language.Here's a sample code in C++
You can do something similar in C# (with some changes), but it isn't possible in JS or Java, without wrapping a variables inside some type of container, and then passing that container.
So in JS or Java, the references to variables can never be passed, rather variables can hold the value of a reference, and that value can get passed.
I'll admit that maybe I'm the one with the massive mental block on this one. Maybe I'm the one who's fighting against the simple solution of the Monty Hall Problem. But every single time someone tries to explain to me why JS has no pass-by-reference, they either ignore the simple, tactical, repeatable examples I've already provided, or they say/show something that actually only furthers my case.
In my first example, I show a basic process by which we 1) initialize two variables, 2) pass those variables into new variables, 3) mutate the new variables, and 4) output the values of the original variables. In the example, the first original variable (the primitive value) is unchanged - because it's passed by value. The second original variable is changed - because it's passed by reference. It's already shown above, but here's a stripped down version of it:
It's obvious that something very different happens to the two original variables -
mostImportantNumber
andspanishNumbers
.We never performed any mutation directly on
mostImportantNumber
and, understandably, the value ofmostImportantNumber
remains constant. We never performed any mutation directly onspanishNumbers
- yet the value ofspanishNumbers
is updated.I don't know how I can make it any clearer than this. It's demonstrably, provably obvious that the newly-created variable
germanNumbers
maintains some kind of "link" back to its initializing variablespanishNumbers
. It's demonstrable and provable because, when we update the members ofgermanNumbers
, the change is reflected back onspanishNumbers
.As long as I've been programming, this "link" has been called a "reference". If you (or anyone else) wants to tell me that this "link" is not a "reference", then that's fine - but that leads me to your question:
Because, in JS (and many other languages), the behavior of a passed primitive is demonstrably different than the behavior of a passed object.
It's really that simple. Why would we keep calling a "kick" a "throw" if it's demonstrably obvious that they're two different behaviors, and two different things are happening in those actions??? And why would we keep calling JS objects that have been passed "pass-by-value" when it's demonstrably obvious that they behave entirely differently from primitives that have been passed by value???
Actually there's no practical difference between how JS passes a primitive value or an object. I'm sorry if I came off wrong. I was just pointing out where a lot of people who were arguing about it where coming from. As for the example you provided.
The JS runtime has no reason to treat a primitive assignment differently to an object assignment. In fact, you can even try to mutate a primitive just like an object, and JS will allow you to do that as well. It just throws away any mutations you make, which is why it appears that you are operating on another copy of the primitive. But in reality both variables point to the same primitive as well.
In fact, if you freeze the object, you can make an object immutable as well, and essentially get the same behavior between objects and primitives, which demonstrates that you don't need to copy anything to make an object behave like a primitive.
I suppose you could say that primitives are like objects that are just frozen by default. While this is technically not true, unless you attempt any operation specific to a primitive (such as addition,subtraction,etc), for the JS Runtime, they are treated exactly in the same way (such as when assigning them to variables or passing them to functions)
I hope that helps clear things up a bit!
I've been noticing that a lot of people who seem entrenched in the idea that "JS has no pass-by-reference" seem to give me examples from C/C++. So I'm honestly wondering if this is just an artifact of people trained in a particular paradigm then (naturally) clinging to that paradigm even when they move outside their original area??
I was curious about how C++ would define pass-by-reference. The IBM Knowledge Center is one of the first pages that comes up: ibm.com/support/knowledgecenter/SS...
It has some very... interesting detail. It starts off with this:
Hmm...
In this JS example, the calling function passes two arguments as parameters to the called function. The called function modifies the value of those arguments. But the change is only reflected on one of those arguments - the object. Why?? Because the object is passed by reference.
The IBM Knowledge Center definition goes on to state that:
So look at exactly what happened in my simple JS example. A modification made to an argument passed in by reference in the called function (
someObject
) has effect in the calling function. Whereas a modification made to an argument passed in by value in the called function (somePrimitive
) does not affect the calling function.There it is, defined by IBM with regard to C++. Even by that definition, JS is passing the object by reference.
If C++ prevents reassignment of a reference to another reference through strong typing enforcement, (been decades since I programmed in C++ so those memories are lost, but a brief survey of the web would indicate that references are static once created in C++.) Maybe that difference is what is confusing to C++ folks about JS reference passing and maybe would get at the heart of why they are stuck on the idea that JS doesn't pass by reference. The difference is in strong versus loose typing not passing by reference. Does that make any sense?
If you CAN destroy a reference and reassign it to another object in C++ then an example that shows it's the same would be equally enlightening.
Yes, this does make sense. I do think that the loose/inferred/runtime typing is what twists everyone's heads in knots.