JS: обновить атрибут последнего добавленного элемента после того, как push() в цикле не присваивает правильное значение

У меня есть следующий код:

var nameData = [{id: "1", name: "George,Steve,Andy"},{id: "2", name: "Andy,Bradley"},{id: "3", name: "George"},{id: "4", name: "Joseph,Julia"}]
var newNames = []
for (var c=0; c<nameData.length; c++) { 
    //create an array of names
    var names = nameData[c].name.toString().split(",")

    //loop through the name array and for each name add a new entry in the newNames array
    for (var n=0; n<names.length; n++) {
            newNames.push(nameData[c])
            newNames[newNames.length-1].name = names[n]
    }                           
}

Мой вывод здесь следующий:

0: {id: "1", name: "Andy"}
1: {id: "1", name: "Andy"}
2: {id: "1", name: "Andy"}
3: {id: "2", name: "Bradley"}
4: {id: "2", name: "Bradley"}
5: {id: "3", name: "George"}
6: {id: "4", name: "Julia"}
7: {id: "4", name: "Julia"}

Однако мой желаемый результат был бы таким:

0: {id: "1", name: "George"}
1: {id: "1", name: "Steve"}
2: {id: "1", name: "Andy"}
3: {id: "2", name: "Andy"}
4: {id: "2", name: "Bradley"}
5: {id: "3", name: "George"}
6: {id: "4", name: "Joseph"}
7: {id: "4", name: "Julia"}

Что-то не так с присвоением атрибута name в цикле. Все записи из одного id получают фамилию в атрибуте name. Почему так и как получить желаемый результат?

Поведение ключевого слова "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
0
30
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы используете newNames.push(nameData[c]);, который передает ссылку на объект. Вместо этого сначала клонируйте объект, а затем нажмите.

var nameData = [{id: "1", name: "George,Steve,Andy"},{id: "2", name: "Andy,Bradley"},{id: "3", name: "George"},{id: "4", name: "Joseph,Julia"}]
var newNames = []
for (var c=0; c<nameData.length; c++) { 
    //create an array of names
    var names = nameData[c].name.toString().split(",")

    //loop through the name array and for each name add a new entry in the newNames array
    for (var n=0; n<names.length; n++) {
            newNames.push(Object.assign({}, nameData[c]));
            newNames[newNames.length-1].name = names[n];
    }                           
}

console.info(newNames);

Вы также можете использовать reduce.

var nameData = [{id: "1", name: "George,Steve,Andy"},{id: "2", name: "Andy,Bradley"},{id: "3", name: "George"},{id: "4", name: "Joseph,Julia"}]

const output = nameData.reduce((accu, {id, name}) => {
    name.split(",").forEach((name) => accu.push({id, name}));
    return accu;    
}, []);

console.info(output);

Это работает. Не могли бы вы добавить какое-то объяснение, почему мой код не будет работать?

JoeBe 04.07.2019 04:47

Основываясь на вашем редактировании: я знаю, что он подталкивает один и тот же объект, но я думал, что, делая newNames[newNames.length-1].name = names[n], я корректирую последний вставленный объект в новый массив newNames и, таким образом, делаю его новым объектом (?)

JoeBe 04.07.2019 04:55

@JoeBe - мне очень жаль. Вы передаете ссылку на объект - newNames.push(nameData[c]). Вместо этого вы можете клонировать объект, а затем нажать - newNames.push(Object.assign({}, nameData[c]));.

random 04.07.2019 05:00

Я только что понял, что это решение по-прежнему неверно, потому что я не поддерживаю атрибуты объекта (например, в вашем примере у меня нет {id: "...", name: "..."}, а скорее {"[value of id]" : "[value of sponsor]"}. Я хочу скопировать объект и просто настроить атрибут name

JoeBe 04.07.2019 05:00

если вам нравятся сокращенные решения, вы можете:

nameData.reduce((a, { id, name: names }) => 
    a.concat(names.split(',').map(name => ({id, name})))
, [])

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

Ваша реализация в low level abstraction, вы делаете это в императиве, поэтому вам нужно обрабатывать слишком много деталей, как loop control, mutate reference и так далее. Я предпочитаю рефакторинг в functional style.

const newNames = nameData.flatMap(data =>
  data.name.split(",").map(name => ({
    id: data.id,
    name
  }))
);

Я думаю, что вы хотите сделать, это: Квартира newData сплит name.

Итак, как вы можете видеть, приведенный выше пример просто квартираКарта это, и вам не нужно обрабатывать детали цикла.

Более того, потому что map или flatMap — неизменяемая функция стиля, и мы получаем новые данные копировать, но не изменять ссылку, нам не нужно заботиться ни о ссылке, ни об изменении исходных данных.

Совет: flatMap — это новая функция от JS, позаботьтесь о совместимости.

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