However the result is like this
// running test
bookLists.indexOf is not a function
bookLists.indexOf is not a function
bookLists.indexOf is not a function
bookLists.indexOf is not a function
// tests completed

I’ll try to explain it and show the difference. But don’t worry if it doesn’t click right away. It’s not an easy concept to grasp quickly.

And don’t feel the need to learn this right now either. It’s not critical. Feel free to let me know if there’s something I didn’t make clear.

I blurred it cuz it contains spoilers.

Two of the main concepts of functional programming are
1. everything is data. We use functions to modify and display that data. Like a sculptor molds clay, so you must mold the data.
2.\ the original data must not be changed (immutability)

So let’s take a look at the requirements. I always list them out like this so that I can knock each out as it’s own function.

If any step requires more steps, then I break it down further. But none of these do.

1. the global array bookList is not changed inside either function
2. The add function should add the given bookName to the end of an array
3. The remove function should remove the given bookName from an array.
4. Both functions should return an array
5. new parameters should be added before the bookName one

Since 1 is an array, and 4 requires we return an array, we know that we can use array methods. Step 5 is just guidance on the parameters. So really we only have 3 requirements

1. Use array methods
2. The add function should add the given bookName to the end of an array
3. The remove function should remove the given bookName from an array.

Ok. So if we were going to code this imperatively, for step 2 (the add function) we’d be saying to ourselves

Using an array of books and the name of a newBook
1. make a copy of the books array
2. push the newBook to the books array
3. return to me the copy of the books array

Whereas declaratively, we’d be saying

Using an array of books and the name of a newBook
1. give me a book array with the new book merged to the end

And that’s it.

But you may wonder if the declarative version is just the question rephrased. It is.

The difference is the key word I used — merged. Remember how I said in functional programming you can only modify data? That means we can’t add to an array. We must merge new data in with the old data, into a new container (immutability).

So once you realize that all you really have to do is merge two arrays together, you can then use the .concat() method on the array object.

From mdn:

The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.

And we get a bonus. Since it returns a new array, you don’t have to worry about creating a copy.

Thanks so much!
I now understand the declarative and imperative programming. In JavaScript, I should write code use the method the MDN provided. It is imperative programming.

I like your leaning technique, it really great!!

about the reduce, I think I do not understand clearly.

why the reduce you return is array with key, but the MDN example returns only numbers.
is it cuz the {} you used as the second argument in the reduce()?

arr.reduce(callback[, initialValue])
I don’t fully understand the syntax, the callback is a function, you use arrow function. The sceond is initialValue, but you set it as a null array.
why the key start at 1?
isn’t it should start at 0?

Exactly! The power of the reduce function is that you can start with whatever object you desire, in whatever shape you desire.

I purposely returned an object to show just that. Good eye picking it up. This is a good indication that you can form mental models.

judyTia:

I should write code use the method the MDN provided. It is imperative programming.

Just to be clear on this, the methods you use don’t determine if it’s imperative. Rather, it’s the patterns you use that determine if it’s declarative or imperative.

The code you used initially was functional as well. Just not as functional as using the methods I showed. This was more of a higher level abstraction.

judyTia:

The sceond is initialValue, but you set it as a null array.

I didn’t start it with a null array, because like you noticed before, I started with an empty object.

judyTia:

I don’t fully understand the syntax, the callback is a function, you use arrow function.

An arrow function is an anonymous function. So writing these are equivalent

const myReducer = function() {}
const myReducer = () => {}
// reference the function
[1,2].reduce(myReducer)
// I can also just place the function directly in the callback
// then I don't need to assign it to a variable
[1,2].reduce(function() {})
// or a fat arrow for readability
[1,2].reduce(() => {})

judyTia:

why the key start at 1?

isn’t it should start at 0?

Because if you provide an initial value to the reduce() method, that will be passed in as the first value. So mentally, it would look like this

// passing an initial value
[ {}, 1, 2 ]
// no initial value
[ 1, 2 ]

So the local variables prev is referencing the previous value, and curr is referencing the next value being passed in. The numbers you saw were not index numbers, but rather the numbers in the array. Take a look at it again. I changed it to make it clearer.

I learn a lot. I now know that the prev at first is {} object, and in JavaScript the object store pattern is like hash map, not like array. Therefore,
A={};
A[4] =1;
They are valid, although the A don’t have index 4, it will automatically add it. A don’t need contain 1 to 3 index at first. It’s not array.

Hint: There are time you have to think another way around to find the solution… its not complex.
I use pure logic to provide a solution to this problem and KISS principle. as JM-Medez mentioned functional programming is declarative and that was already a big hint!