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



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Кажется простой задачей, попытка использовать 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.
currentArray это item1this — пустой массив []map, также инициализируется как другой пустой массив []item1[3], то есть 4this, которое становится [4]this, который «добавляет» это в наш аккумулятор. Итак, наш аккумулятор теперь выглядит как [[4]]. Помните, наш аккумулятор — это массив, и когда мы возвращаем this, он добавляет к нему этот элемент.Все идет нормально? Хорошо, следующий шаг:
currentArray это item2this это [4][thisArg].thisArg, а не копию. Это важно! Теперь давайте выполним обратный вызов
item2[3], то есть 2this, которое становится [4, 2]this, поэтому наш аккумулятор теперь равен [thisArg, thisArg]. Он содержит две ссылки на один и тот же массив! Поскольку thisArg выглядит как [4, 2], значит, аккумулятор выглядит как [[4, 2], [4, 2]]. Помните, что эти элементы не являются двумя разными массивами, это один и тот же массив!Третий шаг должен иметь смысл сейчас.
currentArray это item3this это [4, 2][thisArg, thisArg].item3[3], то есть 5this, который станет [4, 2, 5]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 для получения дополнительной информации.
Что говорит console.info