Добавление двух одинаковых строк в массив вместо изменения только одной из них

Сначала я добавляю две одинаковые строки в массив, а позже мне нужно изменить только последнюю, добавив к ней новое свойство. Как я это делаю:

for(var index in arrayOne) {
   var arrayOneItem = arrayOne[index];
   var new_row = {
      address: arrayOne[index].address,
      date: arrayOne[index].date,
      category: arrayOne[index].category,
   };
   rows.push(new_row);
   if (arrayOne[index].refund_status == 'refunded') {
      rows.push(new_row);
      rows[rows.length - 1].refund_status = 'refunded'; 
   }
}

Но проблема в том, что код внутри оператора if изменяет не только последнюю строку, но и предыдущую, поэтому refund_status = 'refunded' добавляется и к последней, и к предпоследней строке. Почему это происходит и есть ли способ изменить только последнюю строку?

Дополнительное примечание: Избегайте использования оператора in для итерации, иногда массив, являющийся объектом, может содержать дополнительные свойства, не являющиеся индексами. Вместо этого используйте оператор for...of.
Ele 01.07.2019 10:22

@Ele Понятно, что мне использовать вместо этого?

niksrb 01.07.2019 10:24

Пожалуйста, укажите значение arrayOne

dganenco 01.07.2019 10:25
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
57
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Это связано с тем, что объект, который вы вставляете в массив, передается по ссылке, а не по значению, поэтому при изменении исходного объекта вы измените обе ссылки на него в массиве, см. пример ниже:

let someArray = [];
let someObj = {foo: "bar"};
someArray.push(someObj);
someArray.push(someObj);
someArray[0].foo = "baz";
console.info(someArray[1]);

Чтобы избежать этого, вам нужно будет клонировать значения объекта, чтобы создать новый. В вопросе Этот есть несколько способов сделать это, используя JSON.parse и JSON.stringify, это самый короткий способ глубоко скопировать объект без внешней библиотеки, см. пример ниже:

let someArray = [];
let someObj = {foo: "bar"};
someArray.push(someObj);
let newObj = JSON.parse(JSON.stringify(someObj));
someArray.push(newObj);
someArray[0].foo = "baz";
console.info(someArray[1]);
Ответ принят как подходящий

Когда вы используете один и тот же объект дважды, лучше всего создать копию (в данном случае неглубокую) с помощью Object.assign(). Это позволит избежать ссылки на один и тот же объект из нескольких переменных или индексов массива в вашем случае.

например. rows.push(new_row);

становится

rows.push(Object.assign({}, new_row));

Другие решения тоже работают, но это было самым быстрым, а также не сложным

niksrb 01.07.2019 10:39

Потому что вы меняете свойство object, а доступ к object в javaScript осуществляется через ссылку, а не через отдельный экземпляр. Другими словами, у вас есть один и тот же объект в памяти, и вы меняете его свойство. Это означает, что new_row — это объект, который вы создаете и нажимаете несколько раз, и это одно и то же. Вы можете избежать этого, скопировав его при нажатии во второй раз:

if (arrayOne[index].refund_status == 'refunded') {
      rows.push({ ...new_row });
      rows[rows.length - 1].refund_status = 'refunded'; 
   }

где { ...new_row } в основном создает новую копию. Когда вы это сделаете rows[rows.length - 1].refund_status = 'refunded';, изменится только предпоследнее.

Другое решение, которое я бы предложил, немного точнее:

const rows = []; // empty
const arrayOne = []; // SOME DATA HERE as I understand
const refundedStatus = ;

arrayOne.forEach(element=> {
    rows.push(element);

    if (value.refund_status === 'refunded') {
        rows[rows.length].refund_status = 'refunded'; 
        rows.push({ ...element});

    }
});

Другие вопросы по теме