#javascript #arrays
#javascript #массивы
Вопрос:
Я хотел бы отфильтровать массив объектов и обновить некоторое значение для отфильтрованных записей. Вот мой исходный код, без фильтрации:
let obj = {
foo: [
{
bar: "I should be modified",
modify: true,
},{
bar: "I should not be modified",
modify: false,
},{
bar: "I should be modified",
modify: true,
},
],
};
obj.foo.forEach((item, i) => {
let newItem = Object.assign({}, item);
newItem.bar = "I have been modified";
obj.foo[i] = newItem;
});
console.log(obj.foo);
/* Output:
[
{
bar: "I have been modified",
modify: true,
},{
bar: "I have been modified",
modify: false,
},{
bar: "I have been modified",
modify: true,
},
],
*/
Теперь я хотел бы заменить .forEach(...
на .filter(e => e.modify).forEach(...
. Таким образом, вместо изменения всех элементов obj.foo
, изменяются только те, у modify === true
которых. Как это можно сделать без повторной фильтрации внутри цикла forEach?
obj.foo.filter(e => e.modify).forEach((item, i) => {
let newItem = Object.assign({}, item);
newItem.bar = "I have been modified";
obj.foo[i] = newItem; // will not work as the index i is not correct from the original array
});
console.log(obj.foo);
/* Expected output:
[
{
bar: "I have been modified",
modify: true,
},{
bar: "I should not be modified",
modify: false,
},{
bar: "I have been modified",
modify: true,
},
],
*/
/* Actual output:
[
{
bar: "I have been modified",
modify: true,
},{
bar: "I have been modified",
modify: true,
},{
bar: "I should be modified",
modify: true,
},
],
*/
Комментарии:
1. Какой ожидаемый результат здесь? Если вы измените фильтр, как вы измените свойство bar?
2. Я думаю, вам не придется снова фильтровать в цикле forEach независимо. Что не так с добавлением
.filter(e => e.modify).forEach(...
?3. obj.foo.filter((item, i) => { if(item.modify === true) { все, что вы хотите изменить, идет сюда; вернуть элемент; } });
4. Если вы используете
filter
метод, вы потеряете правильный индекс элемента. Таким образом, без фильтрации вы должны проверять с помощьюif
инструкции внутриforEach
обратного вызова.5. вы должны сначала сопоставить его, а затем отфильтровать с помощью сопоставленного индекса … также, пожалуйста, предоставьте свой вывод
Ответ №1:
let obj = {
foo: [
{
bar: "baz",
modify: true,
},{
bar: "bad",
modify: false,
},{
bar: "hello",
modify: true,
},
],
};
const {foo} = obj;
const t = foo.reduce((acc, curr) => {
if (curr.modify) {
curr.bar = "I have been modified";
acc.push(curr);
}
return acc;
}, []);
console.log(t)
Комментарии:
1. Я думаю, что у вас есть ошибка,
acc.push(curr)
которая должна быть вне инструкции if.2. Да, если вам не нужно фильтровать массив с помощью параметра «изменить»
Ответ №2:
Это также можно сделать следующим образом:
obj.foo.filter(e => e.modify).map((item) => {
item.bar = "I have been modified"
});
Я думаю, это должно помочь.
Ответ №3:
Итак, после прочтения всех комментариев, что вы не хотите, чтобы в нем был оператор if и другие вещи, тогда мне приходит в голову эта идея, не изменяя слишком много вашего кода, почему бы не позволить каждому элементу использовать свой собственный исходный индекс, после изменения удалите свойство idx:
let obj = {
foo: [
{
bar: "I should be modified",
modify: true,
},{
bar: "I should not be modified",
modify: false,
},{
bar: "I should be modified",
modify: true,
},
],
};
let index = 0;
obj.foo.filter(e => index amp;amp; e.modify amp;amp; (e.idx = index)).forEach((item, i) => {
let newItem = Object.assign({}, item);
newItem.bar = "I have been modified";
obj.foo[newItem.idx - 1] = newItem;
delete newItem.idx;
});
console.log(obj.foo);