#javascript #node.js
#javascript #node.js
Вопрос:
Хорошо, я буквально понятия не имею, что здесь происходит. Я предполагаю, что это какая-то проблема со ссылкой? Но я не знаю, как обойти это или что его вызывает.
Подводя итог, у меня есть список объектов, а также объект, который предварительно заполняется, чтобы убедиться, что у меня есть данные для всех ключей в объекте.
Мне нужно выполнить итерацию по этому списку объектов, и, используя timeframeId в объекте метаданных и идентификатор в объекте данных, я хочу присвоить весь объект данных соответствующей иерархии timeframeId и id в предварительно заполненном объекте.
По какой-то причине все data
свойства перезаписываются до любой последней строки data
.
Я связал repl, чтобы вы могли убедиться сами: https://repl.it/@ThomasVermeers1/UnwrittenNoisyFirm#index.js
Но мой код выглядит следующим образом:
const buildSegmentsFromRows = (rows, timeframeMetadata, defaultSegmentData) => {
// Prepopulate object to make sure every timeframe has a 'hello' key in it with some data
const emptySegments = timeframeMetadata.reduce((segmentMap, metadata) => {
segmentMap[metadata.timeframeId] = {
metadata,
segments: defaultSegmentData,
};
return segmentMap;
}, {});
// Now simply just loop over the rows, and set [row.metadata.timeframeId].segments[row.data.id] to row.data
const segments = rows.reduce((partialSegments, row) => {
const { timeframeId } = row.metadata;
const { id } = row.data;
/**
* This is the line where everything goes wrong
*/
partialSegments[timeframeId].segments[id] = row.data;
return partialSegments;
}, emptySegments);
return segments;
};
const rows = [
{
metadata: { timeframeId: '20202_01' },
data: {
'id': 'hello', 'value': 15
}
},
{
metadata: { timeframeId: '20202_02' },
data: {
'id': 'hello', 'value': 10
}
}
]
const timeframemetadata = [
{ timeframeId: '20202_01'},
{ timeframeId: '20202_02'}
]
const defaultSegmentData = {
'hello': {
'id': 'hello',
}
}
console.log(JSON.stringify(buildSegmentsFromRows(rows, timeframemetadata, defaultSegmentData), null, 2))
Я ожидаю, что конечный результат будет:
{
"20202_01": {
"metadata": {
"timeframeId": "20202_01"
},
"segments": {
"hello": {
"id": "hello",
"value": 15
}
}
},
"20202_02": {
"metadata": {
"timeframeId": "20202_02"
},
"segments": {
"hello": {
"id": "hello",
"value": 10
}
}
}
}
Но вместо value
этого устанавливается значение 10
во всех экземплярах. Я думаю, это потому, что мы устанавливаем свойство row.data
, которое является ссылкой и обновляется при каждом вызове? Но я здесь в полной растерянности.
Комментарии:
1. На самом деле я не уверен, нужно ли это делать без ссылки, потому что, если вы даже просто замените
partialSegments[timeframeId].segments[id] = row.data;
наpartialSegments[timeframeId].segments[id] = Math.random();
все значения, для них будет установлено одинаковое случайное число.2. Вероятно, вы пытаетесь повторно использовать объект, а не создавать совершенно новый где-то в своем коде. И, таким образом, вы получаете ссылки на один и тот же объект по всей вашей структуре.
Ответ №1:
Проблема в том, что вы ссылаетесь на один и тот же объект для каждого segments
в списке.
Поэтому изменение значения segments[id]
будет обновляться defaultSegmentData
, в результате чего каждая ссылка на defaultSegmentData
также изменится.
const emptySegments = timeframeMetadata.reduce((segmentMap, metadata) => {
segmentMap[metadata.timeframeId] = {
metadata,
segments: defaultSegmentData, // Everything goes wrong here.
};
return segmentMap;
}, {});
Простое решение этой проблемы — избегать использования одной и той же ссылки на объект при создании segmentMap
:
const emptySegments = timeframeMetadata.reduce((segmentMap, metadata) => {
segmentMap[metadata.timeframeId] = {
metadata,
/** Or whatever default value you want.
* Just make sure to create a new instance of it for each call.
*/
segments: {},
};
return segmentMap;
}, {});
Комментарии:
1. Да, это было определенно так. Спасибо за ответ! Просто пошло с: « segments: {…defaultSegmentData }, «