FreeCodeCamp -Refactor Global Variables Out of Functions

Hello, i don’t really need help but i struggled a bit at this exercice.

Link: https://beta.freecodecamp.org/en/challenges/functional-programming/refactor-global-variables-out-of-functions

To do the exercice you have to know how slice() work when doing a copy (called shallow copy) of an array passed in a function argument.

Links:
https://stackoverflow.com/questions/3978492/javascript-fastest-way-to-duplicate-an-array-slice-vs-for-loop

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice

/*
Link: https://beta.freecodecamp.org/en/challenges/functional-programming/refactor-global-variables-out-of-functions
*/

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

//function add a book to the array
function add( bookList, bookName ) {
	//make a copy of the argument's array
	let bookListCopy = bookList.slice(0);
	//add the bookName to the new array
	bookListCopy.push( bookName );
	
	//return the new modified array
	return bookListCopy;
};

//function remove a book from the array
function remove( bookList, bookName ) {
	//make a copy of the argument's array
	let bookListCopy = bookList.slice(0);
	
	if( bookListCopy.indexOf( bookName ) >= 0 ) {
		//delet the book
		bookListCopy.splice( bookListCopy.indexOf( bookName ), 1 );
		
		//return the new modified array
		return bookListCopy;
    }
};

//create a new array from an already existing one but with a new bookName in it
var newBookList = add( bookList, 'A Brief History of Time' );

//create a new array from an already existing one but with a deleted bookName from it
var newerBookList = remove( bookList, 'On The Electrodynamics of Moving Bodies' );

//remove from the bookList at which we added 'A Brief History of Time', the bookName 'On The Electrodynamics of Moving Bodies'
var newestBookList = remove( newBookList, 'On The Electrodynamics of Moving Bodies' );

//["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"];
console.log( bookList );
//["The Hound of the Baskervilles", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"]
console.log( newerBookList );
//["The Hound of the Baskervilles", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae", "A Brief History of Time"]
console.log( newestBookList );

I hope it can help you and save you some time.

13 Likes

There is a bug on this exercice

Function remove() should not use splice() this way, it adds the bookName to the begining of the array, instead or removing it.

return bookList.splice(0, 1, bookName);

The exercice is about refactoring the code to stop altering the global array. If it’s not a bug and the mistake in remove() is made on purpose to make the exercise more challenging this is very confusing

EDIT


Aw look like the issue is known for a long time

3 Likes

^bump

Thank you for this post. This exercise is extremely confusing. Example and instructions don’t match what you have to do.

5 Likes

Thank you for this post.
In addition, I wanted to set an internal variable to equal to the list by using:
function add ( list, bookName) {
var a = list;
a.push(bookName);
}
It appears that I have to use the slice function to create a copy of the bookList.

Thank you @pocahontas123 for pointing out this. I never knew that there was anything like “Deep-copying” an array. Now i learnt alot about it. Another reference to this topic is here :

https://stackoverflow.com/questions/7486085/copying-array-by-value-in-javascript

4 Likes

My function add looks like this:

function add(bookList, bookName) {
return bookList.concat(bookName);
}

concat() function does not change existing array.

2 Likes

use new ES6 spread operator
var a =[…list];//this will creates the copy of array

2 Likes

yes there is bug in splice method in this exercise !
but finally i came up with this solution :slight_smile:

function remove (books, bookName) {
let BL =[…books];
if (BL.indexOf(bookName) >= 0) {

  let bl=[];
   BL.map((a,i)=>{
  if (a!=bookName) {
    bl.push(a);
  }
});
return bl;

// Add your code above this line
}

}

4 Likes

OxiBo
Brilliant. What about the remove function, how did you handle it?
Hope you have a clean solution like the concate function.

It’s confusing but if you read the instructions you’ll understand that it’s asking you to convert the code so that (a) functions should not mutate the global array “bookList” and (b) both functions should return an array . Following what we’ve studied so far (including debugging) you can create a new array variable inside the functions and copy the existing array on it using […array] and after performing the required tasks on it, return the new array. the remove function seems to have a bug either intentionally or not but you can easily figure out and fix it since the value splice needs for index should be equal to the index of the input variable.

function add (arr, bookName) {
let arrNew = […arr];
arrNew.push(bookName);
return arrNew;
}

function remove (arr, bookName) {
let arrNew = […arr];
if (arrNew.indexOf(bookName) >= 0) {

arrNew.splice(arrNew.indexOf(bookName), 1);

}

return arrNew;
}

1 Like

Hello campers ,here is my solution after being so confused about what method should I use :

// 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 (newArr,bookName) { //newArr is the new parameter mentionned above 
    let sliced=newArr.slice(0,); // I have sliced  newArr for copying booklist array 
       sliced.push(bookName); // now I push the string 
    return sliced; // finally I returned the sliced array by the way slice method does not change the origine array
  
  // 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(newArr,bookName) {//here is the same thing as above 
    let slicedTwo=newArr.slice(0,); //also here 
  if (slicedTwo.indexOf(bookName) >= 0) {// here if the condition is true means that the slicedTwo has the string I am looking for
      let index=slicedTwo.indexOf(bookName); //here I want to know the index where this string is living
    
 slicedTwo.splice(index,1); // I use splice method to extract it from my array and this method changes the origine array
    return slicedTwo; //now I return the splicedTwo array
    // 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); //here bookList is not changed because I have made a copy of it .

//"A Brief History of Time"

Hi,

I went with:

// Add your code below this line
function add (a, s) {
var temp = […a];
temp.push(s);
return temp;
// 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 (a, s) {
var temp = […a];
if (temp.indexOf(s) >= 0) {
temp.splice(temp.indexOf(s), 1);
console.log(temp);
return temp;
// Add your code above this line
}
}

If someone could explain why spreading a […a] is needed here i’d very much appreciate it as i’d like to understand destructuring better. Thankyou

1 Like

This was so confusing! This is what I finally put together. I hope they get it fixed soon.

// Add your code below this line
function add (bookList, bookName) {
let copy = […bookList]
copy.push(bookName);
return copy;
// 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) {
let copy = […bookList]
let pos = copy.indexOf(bookName);
if (pos >= 0) {

copy.splice(pos, 1);

// Add your code above this line

Here is my working solution

// 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 (arr, bookName) {
  
  let copyBookList = [...arr];

  copyBookList.push(bookName);

  return copyBookList;

  // 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 (arr, bookName) {

  let copyBookList = [...arr];

  if (copyBookList.indexOf(bookName) >= 0) {
    copyBookList.splice(copyBookList.indexOf(bookName), 1);
    
    return copyBookList
    
    // 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(newestBookList);```

i agree with you :joy:

I finally figured out the problem. The one thing that was tripping me out was that I was trying to copy the argument to a variable like this

let copyBookList = arr; //Which led to indexOf not a function
let copyBookList = [...arr] //This finally let me pass my tests

One thing That I still don’t understand is that why the former code wasn’t able to let me use indexOf but rather the latter one.

Sir I salute you for fixing this challange. See if you can fix this challange https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/es6/create-strings-using-template-literals. It is bugged just like this challange so meaby you can fix this as well.

I’m getting the error .indexOf() is not a function - it happens ONLY when testing the newestBookList variable on the console. I have no idea why.

My code is:

// 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 (list, bookName) {

let newList = list.push(bookName);
return newList;

// 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 (list, bookName) {
if (list.indexOf(bookName) >= 0) {

let i = list.indexOf(bookName);
let a = list.slice(0,i);
let b = list.slice(i+1, list.length-1);
let newList = a.concat(b);
return newList;
// 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);
console.log(newBookList);
console.log(newerBookList);
console.log(newestBookList);

returning a computation tripped me up

Worked:
copiedList.push(bookName);
return copiedList;

Nope:
return copiedList.push(bookName);

same in removed function i just removed any operations from the return statement and got a green checkmark
why this is is beyond me

3 Likes

Thanks mate for your awesome solution