skip to Main Content

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


  1. Seems an easy task, trying to use this as the result array in map doesn’t make sense, this is usually the array being mapped. But in my case I use an arrow function for mapping so this inside it references the outer scope’s this.

    const myArray = [
      [1, 2, 3, 4, 5, 6, 7, 8],
      [8, 7, 5, 2, 4, 6, 1, 6],
      [9, 2, 4, 5, 1]
    ];
    
    const mapIndex = (arr, idx) => arr.map(arr => arr[idx]);
    
    console.log(mapIndex(myArray, 3));
    Login or Signup to reply.
  2. A more minimal form of this is:

    myArray.map(a => a[3])
    

    Where that just selects the index 3 element from each of the sub-arrays.

    Whenever you see a pattern like x = [ ] and later x.push(...) without conditions, you typically have code that can be better expressed as x = y.map(...)

    Login or Signup to reply.
  3. One line solution, .map() already creates a new array for you, so just return the the 4th element of each array like this

    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(x => { return x[3]; });
    
    console.log(newArray);

    or to make it shorter

    let newArray = myArray.map(x => x[3] );
    
    Login or Signup to reply.
  4. because you’re using this inside the map() function without providing an array as the second argument. In this case, map() defaults to using an empty array. and when this 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

    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){
      return currentArray[3];
    });
    
    console.log(newArray);
    
    Login or Signup to reply.
  5. You can also achieve this by using using a simple for loop.

    let myArray = [
         [1, 2, 3, 4, 5, 6, 7, 8],
         [8, 7, 5, 2, 4, 6, 1, 6],
         [9, 2, 4, 5, 1]
        ];
    
    let flattenedArr = [];
    let result = [];
    
    for(let rows = 0; rows < myArray.length; rows++){
        flattenedArr = myArray[rows]
        result.push(flattenedArr[3])
    }
        
    console.log(result)
    
    Login or Signup to reply.
  6. Array.prototype.map() calls its provided callbackFn 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 executing callbackFn. The value you are passing is a new array.

    Let’s rewrite your example code with some variables to make things easier to discuss:

    const item1 = [1, 2, 3, 4, 5, 6, 7, 8];
    const item2 = [8, 7, 5, 2, 4, 6, 1, 6];
    const item3 = [9, 2, 4, 5, 1];
    
    const myArray = [
     item1,
     item2,
     item3,
    ];
    
    const thisArg = [];
    
    const newArray = myArray.map(function callbackFn(currentArray) {
      this.push(currentArray[3]);
      return this;
    }, thisArg);
    

    OK, let’s step through each iteration of the callbackFn call

    1) First Iteration

    • At the start, some values are:
      • currentArray is item1
      • this is an empty array []
      • The "accumulator" that’ll be returned from map also initializes as a different empty array []
    • So we execute the function, which does
      1. Grabs item1[3], which is 4
      2. Pushes that onto this, which becomes [4]
      3. Returns this, which "adds" that to our accumulator. So our accumulator now looks like [[4]]. Remember, our accumulator is an array, and when we return this, it adds that item to it.

    So far so good? OK, next step:

    2) Second Iteration

    • At the start of the 2nd iteration, some values are:
      • currentArray is item2
      • this is [4]
      • The "accumulator" is [thisArg].
    • Notice that the accumulator is just holding a reference to the thisArg, and not a copy. This is important! Now let’s execute the callback
      1. Grabs item2[3], which is 2
      2. Pushes that onto this, which becomes [4, 2]
      3. Returns this, so our accumulator now is [thisArg, thisArg]. It is holding two references to the same array! Since thisArg 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

    • At the start:
      • currentArray is item3
      • this is [4, 2]
      • The "accumulator" is [thisArg, thisArg].
    • Execute:
      1. Grabs item3[3], which is 5
      2. Push that onto this, which becomes [4, 2, 5]
      3. Returns 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 how newArray changes.

    // After your map call...
    newArray[0].push(9);
    
    console.log(JSON.stringify(newArray));
    // logs "[ [4, 2, 5, 9], [4, 2, 5, 9], [4, 2, 5, 9] ]"
    

    See the documentation on map and how the iterative methods (like map) work with the optional thisArg for more info.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search