I would expect newArray
to be [4, 2, 5]
, but instead I get 3 copies of that in a 2D array. It doesn’t seem to match up with what the console.log
says. Why?
let myArray = [
[1, 2, 3, 4, 5, 6, 7, 8],
[8, 7, 5, 2, 4, 6, 1, 6],
[9, 2, 4, 5, 1]
]
let newArray = myArray.map(function(currentArray){
this.push(currentArray[3]);
console.log("this: " + this);
return this;
}, []);
console.log(newArray);
6
Answers
Seems an easy task, trying to use
this
as the result array inmap
doesn’t make sense,this
is usually the array being mapped. But in my case I use an arrow function for mapping sothis
inside it references the outer scope’sthis
.A more minimal form of this is:
Where that just selects the index 3 element from each of the sub-arrays.
Whenever you see a pattern like
x = [ ]
and laterx.push(...)
without conditions, you typically have code that can be better expressed asx = y.map(...)
One line solution,
.map()
already creates a new array for you, so just return the the 4th element of each array like thisor to make it shorter
because you’re using
this
inside themap()
function without providing an array as the second argument. In this case,map()
defaults to using an empty array. and whenthis
is referenced, it actually points to the default empty array. and in each iteration, the empty array gets populated with the fourth element of each subarray and is returned. This leads to the generation of three arrays, each containing the assigned values, resulting in the unexpected output.here’s the correct version of the code
You can also achieve this by using using a simple for loop.
Array.prototype.map()
calls its providedcallbackFn
function once for each element in an array and constructs a new array from the results.In our case, the array we are operating on has 3 elements, so
map
will call the callback 3 times.You also provided a 2nd argument here, which will be used as
this
when executingcallbackFn
. The value you are passing is a new array.Let’s rewrite your example code with some variables to make things easier to discuss:
OK, let’s step through each iteration of the
callbackFn
call1) First Iteration
currentArray
isitem1
this
is an empty array[]
map
also initializes as a different empty array[]
item1[3]
, which is4
this
, which becomes[4]
this
, which "adds" that to our accumulator. So our accumulator now looks like[[4]]
. Remember, our accumulator is an array, and when we returnthis
, it adds that item to it.So far so good? OK, next step:
2) Second Iteration
currentArray
isitem2
this
is[4]
[thisArg]
.thisArg
, and not a copy. This is important! Now let’s execute the callbackitem2[3]
, which is2
this
, which becomes[4, 2]
this
, so our accumulator now is[thisArg, thisArg]
. It is holding two references to the same array! SincethisArg
looks like[4, 2]
, that means that the accumulator looks like[[4, 2], [4, 2]]
. Remember, those elements aren’t two different arrays, they are the same array!The third step should make sense now.
3) Third Iteration
currentArray
isitem3
this
is[4, 2]
[thisArg, thisArg]
.item3[3]
, which is5
this
, which becomes[4, 2, 5]
this
, so our accumulator now is[thisArg, thisArg, thisArg]
, which evaluates to[[4, 2, 5], [4, 2, 5], [4, 2, 5]]
.And we are done! The accumulator is returned, and
newArray
is set to that value.To further prove that
newArray
contains 3 references to the same object, you can mutate that object a fouth time, and watch hownewArray
changes.