6

I'm following some canvas tutorial. The code below is a snippet of that.

In this snippet, why would they not choose for runAnimation to be a simple boolean? I would think the x = !x statement would work anyways, but when i tried changing the code to use booleans, the code didn't work.

So, what's the difference between a boolean as primitive and a boolean as property of an object?

   /*
   * define the runAnimation boolean as an object
   * so that it can be modified by reference
   */
  var runAnimation = {
    value: false
  };

  // add click listener to canvas
  document.getElementById('myCanvas').addEventListener('click', function() {
    // flip flag
    runAnimation.value = !runAnimation.value;
Mark Rensen
  • 129
  • 1
  • 7

1 Answers1

8

All arguments are passed by "value" in JavaScript. This means that when an argument is passed, a copy of what's stored in the variable is passed.

Primitives (like booleans) store the actual data they represent and so, when a primitive is passed, a copy of the data is sent, resulting in two copies of the data. Changes to one, won't affect the other.

But, when you assign an object to a variable, the variable stores the memory location for where that object can be found, not the object itself. Passing an object as an argument results in a copy of the memory address being passed. In these cases, you may wind up with two variables that store the same memory address, so no matter which variable you use, the same one underlying object is affected.

In your scenario, you could certainly make it work with just a boolean variable, but it appears that the tutorial wants to encapsulate that into an object so that copies of the boolean data won't be floating around and there will be less chances of accidentally changing one variable but not another.

Here's some basic examples:

// This function takes a single argument, which it calls "input"
// This argument will be scoped to the function.
function foo(input){
  // The function is going to alter the parameter it received
  input = input + 77;
  console.log(input); 
}

var input = 100;  // Here's a higher scoped variable also called "input"

foo(input);       // We'll pass the higher scoped variable to the function

// Now, has the higher level scoped "input" been changed by the function?
console.log(input);  // 100 <-- No, it hasn't because primitives pass a copy of their data

// ************************************************

// Now, we'll do roughly the same thing, but with objects, not primitives
function foo2(obj){
  obj.someProp = 100;
  console.log(obj.someProp);
}

var obj = {
  someProp : 50
};

foo2(obj);

// Here, we see that the original object has been changed by the funciton we passed it to
console.log(obj.someProp);
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • Thanks, I'm glad to see I was thinking along the correct line, but just wasn't quite there yet. Your examples make it very clear. It's uacutally just like in math, where we use () to cheat the order of calculations. In JS we can use objects to cheat the scope/pass by value. – Mark Rensen Feb 04 '17 at 21:33
  • You said, "Primitives (like booleans) store the actual data they represent and so, when a primitive is passed, a copy of the data is sent, resulting in two copies of the data." Strings are also primitives - does that mean passing a string results in two copies of a string? – Mark Feb 19 '21 at 08:44
  • @Mark If you pass a string primitive, yes. But strings also have an object type, so it depends on which you are dealing with, string vs. String. – Scott Marcus Feb 19 '21 at 12:27
  • @ScottMarcus I'm talking about the string primitive type. So if I have a primitive string of 10 million characters and pass it as the argument to a function, there will now be two strings with millions of bytes duplicated in memory? Isn't that rather inefficient? – Mark Feb 19 '21 at 13:01
  • @Mark As I said, *"If you pass a string primitive, yes"*. In your case, with a string like that, you should create a String object (i.e. `let s = new String("string content here");`) so that you only pass a copy of the object reference to the object in memory without making a copy of the actual string data. – Scott Marcus Feb 19 '21 at 14:29
  • @ScottMarcus OK I think we might be misunderstanding each other. You seem to be describing the Javascript specification but I'm thinking about a typical implementation. Since strings are immutable, wouldn't almost all JS implementations store in the string variable a reference to the memory location of the string content? That is, use the same approach as for object variables, but just make sure the equality operator follows the reference when comparing the string content. – Mark Feb 19 '21 at 16:07
  • @Mark No, this does not happen because that would alter the behavior of code. If I have a string primitive, I need to know that I will be dealing with the actual string data when I interact with a variable (and that I can get a copy by passing it around). This is why we have the option to make a String object or a string primitive, for times when the developer needs the behavior you talk about. The specification does dictate how primitives and objects are to be handled by the implementation. – Scott Marcus Feb 19 '21 at 17:13
  • @ScottMarcus Ah that's interesting - then it seems my understanding of 'immutable' is incorrect. Can you point me to some code which shows that the string data is actually copied, and that there are not simply two references to the same data? – Mark Feb 20 '21 at 01:27
  • @Mark Immutable occurs because the memory allocation for a string really can't be dynamic like it can for other primitives with known memory requirements. If a string were to grow or shrink over time, the system really has no choice but to just create a new memory location of the right size for that new string rather than use the memory of the existing one. However, this is separate and apart from how primatives are passed (by value). There really isn't any way I can think of to demonstrate the by value process because a modifying a copy of a string will create a new one anyway.... – Scott Marcus Feb 20 '21 at 17:14
  • @Mark All I can point you to is the specification which says that the string is a primitive and how primatives should be passed. – Scott Marcus Feb 20 '21 at 17:15