Возможно ли изменять значения массива при выполнении foreach в javascript?

Пример:

var arr = ["one","two","three"];

arr.forEach(function(part){
  part = "four";
  return "four";
})

alert(arr);

Массив все еще имеет исходные значения, есть ли способ получить доступ к элементам массива из функции итерирования?

Ответ 1

Обратному вызову передается элемент, индекс и сам массив.

arr.forEach(function(part, index, theArray) {
  theArray[index] = "hello world";
});

edit - как отмечено в комментарии, .forEach() может принимать второй аргумент, который будет использоваться в качестве значения this при каждом вызове обратного вызова:

arr.forEach(function(part, index) {
  this[index] = "hello world";
}, arr); // use arr as this

Этот второй пример показывает arr само по себе быть настроен как this в обратном вызове. Можно подумать, что массив, участвующий в .forEach() может быть значением по умолчанию this, но по какой-то причине это не так; this будет undefined если второй аргумент не указан.

Также важно помнить, что в прототипе Array предусмотрено целое семейство похожих утилит, и в Stackoverflow всплывает множество вопросов о той или иной функции, так что лучшим решением будет просто выбрать другой инструмент. У тебя есть:

  • forEach для работы с или с каждой записью в массиве;
  • filter для создания нового массива, содержащего только подходящие записи;
  • map для создания нового массива один к одному путем преобразования существующего массива;
  • some чтобы проверить, соответствует ли хотя бы один элемент в массиве некоторому описанию;
  • every чтобы проверить, все ли записи в массиве соответствуют описанию;
  • find для поиска значения в массиве

и так далее. MDN ссылка

Ответ 2

Попробуйте сделать это простым и обсудить, как он работает. Он имеет отношение к переменным типам и функциональным параметрам.

Вот ваш код, о котором мы говорим:

var arr = ["one","two","three"];

arr.forEach(function(part) {
  part = "four";
  return "four";
})

alert(arr);

Прежде всего, здесь вы должны прочитать о Array.prototype.forEach():

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

Во-вторых, расскажем кратко о типах значений в JavaScript.

Примитивы (undefined, null, String, Boolean, Number) сохраняют фактическое значение.

ex: var x = 5;

Типы ссылок (пользовательские объекты) сохраняют расположение памяти объекта.

ex: var xObj = { x : 5 };

И в-третьих, как работают параметры функции.

В функциях параметры всегда передаются по значению.

Поскольку arr - это массив строк, он представляет собой массив примитивных объектов, что означает, что они сохраняются по значению.

Итак, для вашего кода выше это означает, что каждый раз, когда forEach() выполняет итерацию, part равен тому же значению, что и arr[index], , но не тот же объект.

part = "four"; изменит переменную part, но оставит только arr.

Следующий код изменит желаемые значения:

var arr = ["one","two","three"];

arr.forEach(function(part, index) {
  arr[index] = "four";
});

alert(arr);

Теперь, если массив arr был массивом ссылочных типов, следующий код будет работать, потому что типы ссылок сохраняют местоположение памяти объекта вместо фактического объекта.

var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];

arr.forEach(function(part, index) {
  // part and arr[index] point to the same object
  // so changing the object that part points to changes the object that arr[index] points to

  part.num = "four";
});

alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);

Ниже показано, что вы можете изменить part, чтобы указать на новый объект, оставив объекты, сохраненные только в arr:

var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];

arr.forEach(function(part, index) {
  // the following will not change the object that arr[index] points to because part now points at a new object
  part = 5;
});

alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);

Ответ 3

Массив: [1, 2, 3, 4]
Результат: ["foo1", "foo2", "foo3", "foo4"]

Array.prototype.map() Сохранить исходный массив

const originalArr = ["Iron", "Super", "Ant", "Aqua"];
const modifiedArr = originalArr.map(name => '${name}man');

console.log( "Original: %s", originalArr );
console.log( "Modified: %s", modifiedArr );

Ответ 4

Javascript передается по значению и, по существу, означает, что part является копией значения в массиве.

Чтобы изменить значение, обратитесь к самому массиву в вашем цикле.

arr[index] = 'new value';

Ответ 5

Функция .forEach может иметь функцию обратного вызова (eachelement, elementIndex) Итак, в основном, что вам нужно сделать:

arr.forEach(function(element,index){
    arr[index] = "four";   //set the value  
});
console.log(arr); //the array has been overwritten.

Или, если вы хотите сохранить исходный массив, вы можете сделать его копию перед выполнением вышеуказанного процесса. Чтобы сделать копию, вы можете использовать:

var copy = arr.slice();

Ответ 6

замените его на индекс массива.

array[index] = new_value;

Ответ 7

С помощью методов объекта Array вы можете изменить содержимое массива, но по сравнению с базовыми для циклов, эти методы не имеют одной важной функции. Вы не можете изменить индекс в прогоне.

Например, если вы удалите текущий элемент и поместите его в другую позицию индекса в том же массиве, вы можете легко сделать это. Если вы переместите текущий элемент в предыдущую позицию, на следующей итерации нет проблем, вы получите тот же следующий элемент, что и вы ничего не сделали.

Рассмотрим этот код, в котором мы перемещаем элемент в позиции индекса 5 до позиции индекса 2, как только индекс будет считаться до 5.

var ar = [0,1,2,3,4,5,6,7,8,9];
ar.forEach((e,i,a) => {
i == 5 && a.splice(2,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 6 - 7 7 - 8 8 - 9 9

Однако, если мы переместим текущий элемент куда-то за пределы текущей позиции индекса, все становится немного грязным. Тогда самый следующий элемент переместится в позицию перемещенных позиций, а на следующей итерации мы не сможем увидеть или оценить его.

Рассмотрим этот код, в котором мы перемещаем элемент в позиции индекса 5 до позиции индекса 7, как только индекс подсчитывается до 5.

var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && a.splice(7,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 7 - 7 5 - 8 8 - 9 9

Таким образом, мы никогда не встречали 6 в цикле. Обычно в цикле for вы ожидаете уменьшить значение индекса при перемещении элемента массива вперед, чтобы ваш индекс оставался в той же позиции в следующем прогоне, и вы все равно можете оценить элемент, перемещенный в место удаленного предмета. Это невозможно с помощью методов массива. Вы не можете изменить индекс. Проверьте следующий код

var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && (a.splice(7,0,a.splice(i,1)[0]), i--);
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 4 5 - 6 7 - 7 5 - 8 8 - 9 9

Как вы видите, когда мы уменьшаем i, он не будет продолжаться с 5, а 6, откуда он остался.

Так что имейте это в виду.

Ответ 8

Здесь аналогичный ответ с использованием функции стиля =>:

var data = [1,2,3,4];
data.forEach( (item, i, self) => self[i] = item + 10 );

дает результат:

[11,12,13,14]

Параметр self не является обязательным для функции стиля стрелки, поэтому

data.forEach( (item,i) => data[i] = item + 10);

тоже работает.

Ответ 9

Чтобы полностью добавить или удалить элементы, которые могли бы изменить индекс, с помощью расширения zhujy_8833 предложения slice() для итерации по копии, просто посчитайте количество элементов, которые вы уже удалили или добавили, и измените индекс соответствующим образом. Например, чтобы удалить элементы:

let values = ["A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8"];
let count = 0;
values.slice().forEach((value, index) => {
    if (value === "A2" || value === "A5") {
        values.splice(index - count++, 1);
    };
});
console.log(values);

// Expected: [ 'A0', 'A1', 'A3', 'A4', 'A6', 'A7', 'A8' ]

Чтобы вставить элементы перед:

if (value === "A0" || value === "A6" || value === "A8") {
    values.splice(index - count--, 0, 'newVal');
};

// Expected: ['newVal', A0, 'A1', 'A2', 'A3', 'A4', 'A5', 'newVal', 'A6', 'A7', 'newVal', 'A8' ]

Чтобы вставить элементы после:

if (value === "A0" || value === "A6" || value === "A8") {
    values.splice(index - --count, 0, 'newVal');
};

// Expected: ['A0', 'newVal', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'newVal', 'A7', 'A8', 'newVal']

Чтобы заменить элемент:

if (value === "A3" || value === "A4" || value === "A7") {
    values.splice(index, 1, 'newVal');
};

// Expected: [ 'A0', 'A1', 'A2', 'newVal', 'newVal', 'A5', 'A6', 'newVal', 'A8' ]

Примечание: если реализованы вставки 'before' и 'after', код должен обрабатывать вставки 'before' сначала, иначе все будет не так, как ожидалось