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);

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);

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