Let newArr = bookList;

Tell us what’s happening:
I already solved this on my own but I would like some clarification so that I might better understand the circumstances of why my first attempt to solve this failed.

In the add function I wrote let newArr = bookList; and tried to finish the add function modifying the newArr variable that I declared inside of the function but noticed that the Global variable bookList was being modified as well. The result was , the book name argument would show up twice at the end of the global variable and the local variable.

So my question is:

was this happening because arrays are passed by reference and the local variable I declared was tied to the global variable? did setting newArr equal to book list make it a pointer?

I hope I made my question clear, and thank you for taking time to read this.

Your code so far

// The global variable
var bookList = ["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"];

// Change code below this line
function add (arr, bookName) {
let newArr = arr.slice(); 
return newArr;

// Change code above this line

// Change code below this line
function remove (arr,bookName) {
var book_index = bookList.indexOf(bookName);
if (book_index >= 0) {
  let new_arr = arr.slice();
  new_arr.splice(book_index, 1);
  return new_arr;

  // Change code above this line

var newBookList = add(bookList, 'A Brief History of Time');
var newerBookList = remove(bookList, 'On The Electrodynamics of Moving Bodies');
var newestBookList = remove(add(bookList, 'A Brief History of Time'), 'On The Electrodynamics of Moving Bodies');



Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36.

Challenge: Refactor Global Variables Out of Functions

Link to the challenge:

Wow, you’re the first person to not instantly understand this.

Oh wait, the opposite of that. Everyone gets tripped up on this.

It has to do with how variables are stored. If you’d started out with a low level language, then you’d have to manage memory and addresses and be very aware of how that data is handled and passed around. But the great/horrible thing about JS is that it does that all for you so you don’t have to think about it. But it helps to know the basics.

There are two ways to store data in a variable, by value or by reference. In JS, all primitives (strings, numbers, booleans, etc.) are stored by value, That means that the variable holds the actual value. This makes sense - this is what people assume would happen.

Anything in JS that is not a primitive is an object. (Remember that in JS, things like arrays and functions are just specialized objects.) Objects are stored by reference, or the address of a memory location. This kind of makes sense - if JS needs to store a number, no problem - just allocate 64 bits. But how much space do you allocate for an array? Arrays can grow. So instead, you store the reference in the variable and you let JS handle growing and shrinking and moving around the memory location to which that points.

In JS, primitives are by value and everything else is some kind of object and is by reference.

Say that 100 times.

So, when you have:

const arr1 = [1, 2, 3];
const arr2 = arr1;

That will affect “both” arrays because there really is only one array. When you did arr2 = arr1 you just copied the reference. They both point to the same location in memory. There is only one array with two variables pointing to it. So arr2.push(4) goes out to that memory location and pushes on that data.

So, how do you get the effect that you want, a copy or clone of the original array? There are a couple of ways.

const arr2 = arr1.slice();
const arr2 = [...arr1];
const arr2 = Array.from(arr1);

These are the most common ways. That will create a copy of that array and store that new arrays memory reference in arr2.

This will work if you have a “shallow” array, in otherwords, none of the elements in the array are themselves reference types, then you have the same problem. You can have nested reference types inside nested reference types, ad infinitum, turtles all the way down. There are tricks for “deep cloning”, but let’s not worry about that here.

On the subject of reference types, one thing you may have notice in the code I wrote:

const arr2 = arr1;

Wait, how can I change arr2 with a push? That makes no sense? You can’t change a constant. But that’s because I’m not changing the variable, I’m changing the memory to which it points. That is a very important distinction. If I’d done this:

const arr2 = arr1;
arr2 = [9, 8, 7];

that would have been a problem, I would have been creating a new array, in a new memory location with a new address (reference) and (and this is the problem) assigning it into a variable that was declared as a constant. I am allowed to change the memory that it points to (that was not declared as a constant) but I cannot change the reference.

It’s an odd distinction, but that’s why you see people declaring arrays and objects as const even though they are changing them. As long as you don’t try to change the memory location to which they point, JS is cool with it.

I hope that helps.


I recently wrote a short blog post on this very thing, https://tobycodes.tech/posts/var-and-const

1 Like

OH yea that helped , its definitely what I thought then, I had a feeling that’s what was happening, when I saw that using the slice() method got rid of that problem, but didn’t know for sure. I learned some about pointers and memory location in cs50 (which I did not finish) .

Also thank you for explaining the difference in changing the memory at a particular location versus changing the cons variable itself. That makes it 100 times more clear.

I really appreciate you taking the time to write this for me. It gave me the clarification I needed and now I feel that I can trust my gut feeling more in the fututre.