Javascript ES6 / ES5 знайти у масиві та зміни


133

У мене є масив об’єктів. Я хочу знайти якесь поле, а потім змінити його:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

var foundItem = items.find(x => x.id == item.id);
foundItem = item;

Я хочу, щоб він змінив оригінальний об’єкт. Як? (Мені байдуже, чи буде це в лодаші)


Дозує ваш новий об'єкт itemмістить idключ? чи Ви не заперечуєте, щоб ідентифікатор, а також усі властивості itemоб’єкта в записі масиву?
Koushik Chatterjee

Відповіді:


251

Ви можете використовувати findIndex для пошуку індексу в масиві об'єкта та заміни його за необхідністю:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

var foundIndex = items.findIndex(x => x.id == item.id);
items[foundIndex] = item;

Це передбачає унікальні ідентифікатори. Якщо ваші посвідчення особи дублюються (як у вашому прикладі), можливо, краще, якщо ви використовуєте для ForEach:

items.forEach((element, index) => {
    if(element.id === item.id) {
        items[index] = item;
    }
});

16
@georg Це поверне новий масив.
CodingIntrigue

3
Функція => не працюватиме в IE11. Нещодавно покусаний цим.
Lewis Cianci

1
можливо, краще буде використовувати letключове слово замістьvar
Інус Саха

Тільки FYI, це не працює в деяких версіях phantomJS
Sid

1
Я віддаю перевагу більш багатослівний метод @CodingIntrigue використовує замість того, mapщоб використовувати однолінійний, який використовує @georg. Потрібно менше розумової гімнастики, щоб зрозуміти, що відбувається. Варто зайвого рядка коду.
Джошуа Пінтер

44

Мій найкращий підхід:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

items[items.findIndex(el => el.id === item.id)] = item;

Довідка для пошукуIndex

І якщо ви не хочете замінити новий об'єкт, а замість цього скопіювати поля item, ви можете використовувати Object.assign:

Object.assign(items[items.findIndex(el => el.id === item.id)], item)

як альтернатива з .map():

Object.assign(items, items.map(el => el.id === item.id? item : el))

Функціональний підхід :

Не змінюйте масив, використовуйте новий, щоб не створювати побічні ефекти

const updatedItems = items.map(el => el.id === item.id ? item : el)

1
Будь ласка, посилання на англійську сторінку, якщо оригінальне запитання було англійською мовою. Також цей приклад передбачає, що об'єкт завжди знайдений.
raarts

1
Ви завжди можете обернути це у вираз спроб упіймання, то ... правда?
Soldeplata Saketos

1
І будучи абсолютно дослівним до питання публікацій, він хоче відредагувати елемент у масиві. Він не хоче знати, чи існує він чи ні, тому ми припускаємо, що він це робив раніше.
Солдеплата Сакетос

@SoldeplataSaketos так, ви можете загорнути його в try/catch, але не слід, тому що пошук елемента не є винятковим випадком; це стандартний випадок, який слід враховувати, перевіряючи значення повернення, findIndexа потім оновлюючи масив лише тоді, коли елемент був знайдений.
Уейн

20

Інший підхід - використовувати сплайс .

splice()Метод змінює вміст масиву шляхом видалення або заміни існуючих елементів і / або додавання нових елементів на місці .

Примітка: Якщо ви працюєте з реактивними рамками, він оновить "перегляд", ваш масив "знаючи", ви оновили його.

Відповідь:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

let foundIndex = items.findIndex(element => element.id === item.id)
items.splice(foundIndex, 1, item)

І якщо ви хочете змінити лише значення елемента, ви можете скористатися функцією find :

// Retrieve item and assign ref to updatedItem
let updatedItem = items.find((element) => { return element.id === item.id })

// Modify object property
updatedItem.aProp = ds.aProp

14

З огляду на змінений об’єкт та масив:

const item = {...}
let items = [{id:2}, {id:3}, {id:4}];

Оновіть масив новим об’єктом шляхом ітерації через масив:

items = items.map(x => (x.id === item.id) ? item : x)

Будь ласка, не просто вставляйте код. Поясніть, що робиться, і як це вирішує питання.
Спенсер

1
Я думаю, що це найкраще рішення, оскільки воно має найкращу ефективність, оскільки він переходить через масив лише один раз, а також змінить посилання на масив, тому уникне змінних ситуацій
Охад Садан

6

Можливо використовувати Filter .

const list = [{id:0}, {id:1}, {id:2}];
let listCopy = [...list];
let filteredDataSource = listCopy.filter((item) => {
       if (item.id === 1) {
           item.id = 12345;
        }

        return item;
    });
console.log(filteredDataSource);

Масив [Object {id: 0}, Object {id: 12345}, Object {id: 2}]


Мені подобається фільтр, тому що він дозволяє створити новий масив, а для цього також неіснуючі записи 'видалені'
pungggi

0

працював на мене

let returnPayments = [ ...this.payments ];

returnPayments[this.payments.findIndex(x => x.id == this.payment.id)] = this.payment;

1
Будь ласка, не просто вставляйте код. Поясніть, що робиться, і як це вирішує питання.
Адріан Мол

Прийнята найбільш схвалена відповідь не сильно відрізняється, але ви не вказували на те, щоб вони оновлювали там відповідь .. чому це так?
li x

0

Хоча більшість існуючих відповідей чудові, я хотів би включити відповідь, використовуючи традиційний для циклу, який також слід враховувати тут. ОП вимагає відповіді, яка сумісна з ES5 / ES6, і застосовується традиційна для циклу :)

Проблема використання функцій масиву в цьому сценарії полягає в тому, що вони не мутують об'єкти, але в цьому випадку мутація є обов'язковою умовою. Підвищення ефективності використання традиційного циклу - це просто (величезний) бонус.

const findThis = 2;
const items = [{id:1, ...}, {id:2, ...}, {id:3, ...}];

for (let i = 0, l = items.length; i < l; ++i) {
  if (items[i].id === findThis) {
    items[i].iAmChanged = true;
    break;
  }
}

Хоча я є великим прихильником функцій масиву, не дозволяйте їм бути єдиним інструментом у вашій панелі інструментів. Якщо метою є мутація масиву, вони не найкраще підходять.


0

Одне вкладиш за допомогою оператора розкидання

 const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.