Пример:
var arr = ["one","two","three"];
arr.forEach(function(part){
part = "four";
return "four";
})
alert(arr);
Массив все еще имеет исходные значения, есть ли способ получить доступ к элементам массива из функции итерирования?
Пример:
var arr = ["one","two","three"];
arr.forEach(function(part){
part = "four";
return "four";
})
alert(arr);
Массив все еще имеет исходные значения, есть ли способ получить доступ к элементам массива из функции итерирования?
Обратному вызову передается элемент, индекс и сам массив.
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 ссылка
Попробуйте сделать это простым и обсудить, как он работает. Он имеет отношение к переменным типам и функциональным параметрам.
Вот ваш код, о котором мы говорим:
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);
Массив: [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 );
Javascript передается по значению и, по существу, означает, что part
является копией значения в массиве.
Чтобы изменить значение, обратитесь к самому массиву в вашем цикле.
arr[index] = 'new value';
Функция .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();
замените его на индекс массива.
array[index] = new_value;
С помощью методов объекта 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, откуда он остался.
Так что имейте это в виду.
Здесь аналогичный ответ с использованием функции стиля =>
:
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);
тоже работает.
Чтобы полностью добавить или удалить элементы, которые могли бы изменить индекс, с помощью расширения 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' сначала, иначе все будет не так, как ожидалось