Refactor Global Variables Out of Functions problem

Tell us what’s happening:
In the two functions, I have used a value to copy the original array as to not modify it, defining newVar and newVar2 inside the functions, but I get the error that newVar is not defined.

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"];

/* This function should add a book to the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function add (bookList, bookName) {
  var newVar = [];
  newVar = bookList;
  return newVar.push(bookName);
  
  // Add your code above this line
}

/* This function should remove a book from the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function remove (bookList, bookName) {
  if (bookList.indexOf(bookName) >= 0) {
    var newVar2 = [];
    newVar2 = bookList;
    return newVar.splice(0, 1, bookName);
    
    // Add your 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');

console.log(bookList);

Your browser information:

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

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/functional-programming/refactor-global-variables-out-of-functions

var newVar2 = [];
    newVar2 = bookList;
    return newVar.splice(0, 1, bookName);

newVar is not visible in the remove function, perhaps you meant newVar2?

Edit for formatting

I edited it, but still get “bookList.indexOf is not a function” as an error.

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

/* This function should add a book to the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function add (bookList, bookName) {
  var newVar = [];
  newVar = bookList;
  return newVar.push(bookName);
  
  // Add your code above this line
}

/* This function should remove a book from the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function remove (bookList, bookName) {
  if (bookList.indexOf(bookName) >= 0) {
    var newVar2 = [];
    newVar2 = bookList;
    return newVar2.splice(0, 1, bookName);
    
    // Add your 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');

console.log(bookList);

Unfortunately, copying array doesn’t have any convenient syntax like that. (There is a shorter syntax though)

In your code, newVar still refers to bookList, so any change made to newVar still affects bookList. This is because the way an array is passed as an argument works different from other primitive types. So, the only way to copy an array or object is constructing a new one.

For more reading, you can search for the topic “Javascript pass by value and pass by reference”
In a nutshell, when an object is passed as an argument, a copy of the object’s reference is passed rather than a copy of object. So, you can still modify the original object inside a function.

Continuing on your new problem.

You get this message, bookList.indexO is not a function... because of your add()
Notice this code uses its first argument as the output of add()

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

What does add() return? It is certainly not an array. Whatever returned from add() doesn’t have indexOf(). Therefore, bookList.indexOf is undefined, which is obviously not a function.

I think I have figured out how to copy the array without referencing. Is this correct?

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

/* This function should add a book to the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function add (bookList, bookName) {
  var newVar = "";
  newVar = JSON.parse(JSON.stringify(bookList);
  return newVar.push(bookName);
  
  // Add your code above this line
}

/* This function should remove a book from the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function remove (bookList, bookName) {
  if (bookList.indexOf(bookName) >= 0) {
    var newVar2 = "";
    newVar2 = JSON.parse(JSON.stringify(bookList));
    return newVar2.splice(0, 1, bookName);
    
    // Add your 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');

console.log(bookList);

You are over complicating your functions with the JSON.parse/JSON.stringify part. Read about slice for making shallow copies of arrays.

The main problem with your add function code (besides the missing closing parentheses of your JSON.parse), is your return statement (seen below):

return newVar.push(bookName);

The push method returns the length of the array after the element specified has been added to the array, so the above returns a number instead of an array. Put the push on a separate line and then return just the array. Another option is to read about the concat method.

The remove function logic is not correct, because your splice always removes the first element in the array and replaces it with bookName. You should only be removing bookName (regardless of what position in the array it is located) and definitely not be adding it the book back in as the array’s first element.

Okay, I have put the push methods on different lines, while also modifying what I wrote in splice, but something is still not working, I think that somewhere I am still getting as a result a number, instead of an array. Or I did not understand these explanations correctly.

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

/* This function should add a book to the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function add (bookList, bookName) {
  var newVar = "";
  newVar = bookList.slice();
 var result = newVar.push(bookName);
 return result; 
  // Add your code above this line
}

/* This function should remove a book from the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function remove (bookList, bookName) {
  if (bookList.indexOf(bookName) >= 0) {
    var newVar2 = "";
    newVar2 = bookList.slice();
    var result1 = newVar2.splice(bookList.indexOf(bookName), 1);
    return result1;
    
    // Add your 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');

console.log(bookList);

You have the exact same problem I described in the third paragraph of my original reply. You are assigning the return value of the push method to the result variable. The push method returns a number which is the length of the array after the push has added the new value.
So when you write return result, you are not returning an array. Instead, you are just returning a number.

In my last reply I stated “Put the push on a separate line and then return just the array.” You are not returning an array.

When you are entangled, it is almost always beneficial to think outside of the code; just think about what you should do for each function without getting too technical. You are not so far away. For example,

add(books, book)
    make copy of books
    add book to the copy
    return the copy

remove(books, book) {
    make a copy of books
    find book from the copy, then remove it
    return the copy
}

Notice both operation returns array, this is required by the challenge.

Notice remove() still returns a copy whether book is inbooks or not. This is because, if you return the original array, any operations performed on the return value of remove() can still modify the original array.

I tried some more, and managed to get the first two requirements down, after figuring out how push actually works, but when I tried tinkering with remove, they would’t be fine anymore. I’m not sure if that is the way to choose the index in splice, but it says that bookListCopy2 is not defined.

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

/* This function should add a book to the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function add (x, bookName) {
  var bookListCopy=JSON.parse(JSON.stringify(x))
  bookListCopy.push(bookName);
  return bookListCopy;
  
  // Add your code above this line
}

/* This function should remove a book from the list and return the list */
// New parameters should come before the bookName one

// Add your code below this line
function remove (y, bookName) {
  var bookListCopy2 = JSON.parse(JSON.stringify(y));
  if (bookListCopy2.indexOf(bookName) >= 0) {
    
    bookListCopy2.splice(booklistCopy2.indexOf(bookName), 1,);
    return bookListCopy2;
    
    // Add your 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');

console.log(bookList);

It is booklistCopy2 that is undefined not bookListCopy2.

You don’t need to distinguish names between bookListCopy and bookListCopy2. Why would you do this?
Frankly, bookListCopy is too long. You don’t need long name in this case; the context makes it clear that any copy would be the copy of bookList.

You want to store the result of costly operation like indexOf() and reuse it in the future.

If you are unsure about a particular function, then search about it.

2 Likes