I want to understand why do I have to use the slice method

I want to understand exactly why do I have to use the slice method when I am assigning the parameter arr2 to arr because not inserting it will not make me pass the challenge
the challenge link for the question
function frankenSplice(arr1, arr2, n) {

let arr = arr2.slice();

arr.splice(n, 0, …arr1)

console.log(arr)

return arr

}

frankenSplice([1, 2, 3], [4, 5, 6], 1);

If I get rid of that slice and just work on arr2:

function frankenSplice(arr1, arr2, n) {
  arr2.splice(n, 0, ...arr1)
  return arr2
}

I get the right result, but I fail this test:

The second array should remain the same after the function runs.

So, arr2 is being changed. Why?

When I look up splice I see:

The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.

That means that it is changing the array that is being passed, not just here, but everywhere. Remember that in JS, all objects (including arrays) are reference types so when we pass them to the function, we are passing them “by reference”. That means that we aren’t passing the array, but passing an address (reference) to that memory. In the function, we are making changes to the data at that address, which is the same address that was passed.

A good principle is that you don’t want to mutate the data that is passed to you. So, we want to make a copy that we can manipulate. Making a copy of a reference type in JS is not a simple thing. For example, this:

let arr = arr2;

will just copy the address so it is still pointing to the same data. For example:

const arr1 = [1, 2, 3];
const arr2 = arr1;
arr2[0] = 'ribbit';
console.log(arr1);
// ['ribbit', 2, 3]

So, we need to make a copy, or “clone” the array. That can be tricky in JS, but fortunately we only need a shallow clone because this is a simple array of primitive types.

One easy way to do a shallow clone of an array is with slice. Note that the description says:

The slice() method returns a shallow copy of a portion of an array into a new array object selected from start to end ( end not included) where start and end represent the index of items in that array. The original array will not be modified.

And since we aren’t sending any parameters, the “portion” is the entire array. So we get a new copy of the whole array.

There are other ways to do it (like with map or filter) but a few other common ones are:

const arr = arr2.concat()

// or

const arr = Array.from(arr2);

But probably more common nowadays would be to use ES6:

const arr = [...arr2]'

Does that make sense?

2 Likes

Thanks for your great answer you made me understand specific parts that I wans confused about it and tried to learn it from different courses and I couldn’t grasp it

may I ask you to give me more details about the shallow
thanks for your time and help

In this sense, shallow just means that we are copying on the first level. For example, if we have an array of arrays:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

const arrAll = [arr1, arr2];

What does it mean to copy arrAll? Do we want just a new array but have the values contained in the same? With primitives it is easy because we are copying their values. But if I make a copy of arrAll, does that mean that I want the references to arr1 and arr2 to stay the same or do I want shallow copies of those too?

In the first case, the shallow copy:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

const arrAll = [arr1, arr2];
const arrAll2 = [...arrAll];

console.log(arrAll === arrAll2);
// false

console.log(arrAll[0] === arrAll2[0]);
// true

console.log(arrAll[1] === arrAll2[1])
// true

arrAll[0] = ['a', 'b', 'c'];
console.log(arrAll[0]);
// ['a', 'b', 'c']
console.log(arrAll2[0]);
// [1, 2, 3]

arrAll[1][0] = 'ribbit';
console.log(arrAll[1]);
// ['ribbit', 5, 6]
console.log(arrAll2[1]);
// ['ribbit', 5, 6]

So, this kind of copying (shallow copy or shallow clone) just does a true copy at the first level, the level of the arrAll, but if there are reference types on the level below it, they will not be “copies” in the sense that we mean. True, the reference (address) will be copied, but as discussed before, it is still pointing to the same place in memory so any changes made to that spot in memory will affect all reference types that are pointing to that spot in memory. For a true, “deep” copy/clone, we would need to go recursively through the data structure and make new copies of all the reference types. Since in this case we know we only have two levels, we could just do this:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

const arrAll = [arr1, arr2];
const arrAll2 = arrAll.map(arr => [...arr]);

console.log(arrAll === arrAll2);
// false

console.log(arrAll[0] === arrAll2[0]);
// false

console.log(arrAll[1] === arrAll2[1])
// false

arrAll[0] = ['a', 'b', 'c'];
console.log(arrAll[0]);
// ['a', 'b', 'c']
console.log(arrAll2[0]);
// [1, 2, 3]

arrAll[1][0] = 'ribbit';
console.log(arrAll[1]);
// ['ribbit', 5, 6]
console.log(arrAll2[1]);
// [4, 5, 6]

Now we have a true “deep” copy. Notice the last two log statements. As said, this only works if there are two levels, “array or arrays” (or objects or a different reference type). If you don’t know the depth, then you need some kind of recursive solution.

Which is a better copy? Shallow or deep? It depends. Sometimes you definitely want one, sometimes you definitely want the other. It just depends on your needs. But you should be aware of the difference.

Don’t get frustrated if this is a little confusing. Even experienced devs sometimes have to stop and thing about it from time to time.

Another example of a shallow clone would be an address book. Let’s say I have an address book and you want a copy. I would just copy over those addresses. They would still point to the same house. If you looked up my address for Amy Andersen and went to it and painted her house blue, the house to which my address for Amy Andersen is pointing is also now blue - they are the same address, just in two different address books.

A deep copy of an address book would mean building a completely new house with all new stuff that are an exact copy of the old house with all new stuff - but everything is an exact copy. So, if we repainted one house, the other would not be affected. It has a new address but it is listed under Amy Andersen and before any changes are made, standing in those houses, you cannot tell the difference. But any change made to one does not affect the other - they are two different houses with different addresses - they are copies, but they are separate.

Of course, a deep copy doesn’t make sense in the context of an address book, but I hope it makes clearer the distinction.

1 Like