Javascript map() в 2D-массиве

Я ожидал, что newArray будет [4, 2, 5], но вместо этого я получаю 3 копии этого в 2D-массиве. Кажется, это не совпадает с тем, что говорит console.info. Почему?

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.info("this: " + this);
  return this;
}, []);

console.info(newArray);

Что говорит console.info

Navitas28 26.05.2023 17:14
this в вашем примере — это новый массив, и, поскольку ваш обратный вызов возвращает его, все элементы становятся ссылками на этот массив.
InSync 26.05.2023 17:14

Метод .map() неявно создает новый массив. Все, что нужно сделать вашей функции, это return currentArray[3];

Pointy 26.05.2023 17:14
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
55
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Кажется простой задачей, попытка использовать this, поскольку массив результатов в map не имеет смысла, this обычно является отображаемым массивом. Но в моем случае я использую стрелочную функцию для сопоставления, поэтому this внутри нее ссылается на 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.info(mapIndex(myArray, 3));

Более минимальная форма этого:

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

Где это просто выбирает элемент индекса 3 из каждого из подмассивов.

Всякий раз, когда вы видите такой шаблон, как x = [ ] и более поздние x.push(...) без условий, у вас обычно есть код, который может быть лучше выражен как x = y.map(...)

Однострочное решение, .map() уже создает для вас новый массив, поэтому просто верните 4-й элемент каждого массива, как это

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.info(newArray);

или сделать короче

let newArray = myArray.map(x => x[3] );

потому что вы используете this внутри функции map() без указания массива в качестве второго аргумента. В этом случае map() по умолчанию используется пустой массив. и когда на 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(function(currentArray){
  return currentArray[3];
});

console.info(newArray);

Вы также можете добиться этого, используя простой цикл for.

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.info(result)
Ответ принят как подходящий

Array.prototype.map() вызывает предоставленную callbackFn функцию один раз для каждого элемента в массиве и строит новый массив из результатов.

В нашем случае массив, с которым мы работаем, состоит из 3 элементов, поэтому map вызовет обратный вызов 3 раза.

Вы также указали здесь второй аргумент, который будет использоваться как this при выполнении callbackFn. Значение, которое вы передаете, является новым массивом.

Давайте перепишем код вашего примера с некоторыми переменными, чтобы упростить обсуждение:

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);

Хорошо, давайте пройдемся по каждой итерации вызова callbackFn.

1) Первая итерация

  • В начале некоторые значения:
    • currentArray это item1
    • this — пустой массив []
    • «Накопитель», который будет возвращен из map, также инициализируется как другой пустой массив []
  • Итак, мы выполняем функцию, которая делает
    1. Хватает item1[3], то есть 4
    2. Подталкивает это к this, которое становится [4]
    3. Возвращает this, который «добавляет» это в наш аккумулятор. Итак, наш аккумулятор теперь выглядит как [[4]]. Помните, наш аккумулятор — это массив, и когда мы возвращаем this, он добавляет к нему этот элемент.

Все идет нормально? Хорошо, следующий шаг:

2) Вторая итерация

  • В начале второй итерации некоторые значения:
    • currentArray это item2
    • this это [4]
    • «Аккумулятор» — это [thisArg].
  • Обратите внимание, что аккумулятор просто содержит ссылку на thisArg, а не копию. Это важно! Теперь давайте выполним обратный вызов
    1. Хватает item2[3], то есть 2
    2. Подталкивает это к this, которое становится [4, 2]
    3. Возвращает this, поэтому наш аккумулятор теперь равен [thisArg, thisArg]. Он содержит две ссылки на один и тот же массив! Поскольку thisArg выглядит как [4, 2], значит, аккумулятор выглядит как [[4, 2], [4, 2]]. Помните, что эти элементы не являются двумя разными массивами, это один и тот же массив!

Третий шаг должен иметь смысл сейчас.

3) Третья итерация

  • В начале:
    • currentArray это item3
    • this это [4, 2]
    • «Аккумулятор» — это [thisArg, thisArg].
  • Выполнять:
    1. Хватает item3[3], то есть 5
    2. Нажмите это на this, который станет [4, 2, 5]
    3. Возвращает this, так что наш аккумулятор теперь равен [thisArg, thisArg, thisArg], который оценивается как [[4, 2, 5], [4, 2, 5], [4, 2, 5]].

И мы закончили! Аккумулятор возвращается, и newArray устанавливается на это значение.

Чтобы дополнительно доказать, что newArray содержит 3 ссылки на один и тот же объект, вы можете изменить этот объект в четвертый раз и посмотреть, как изменится newArray.

// After your map call...
newArray[0].push(9);

console.info(JSON.stringify(newArray));
// logs "[ [4, 2, 5, 9], [4, 2, 5, 9], [4, 2, 5, 9] ]"

См. документацию по карте и тому, как итерационные методы (например, map) работают с необязательным аргументом thisArg для получения дополнительной информации.

Другие вопросы по теме