#javascript #json #object #instance #key-value
#javascript #json #объект #экземпляр #ключ-значение
Вопрос:
Я пытаюсь обновить элементы в существующем экземпляре объекта. Когда я это делаю, некоторые из того, что, как я полагаю, является унаследованными характеристиками, отображаются в proto в инструментах разработки Chrome.
//this is a Chrome Dev Tools view of the instantiated object I attempted to update/modify;
//this is rejected by a later function I'm using in the xAPI tincan-min.js library
statement.target.definition.choices: Array(5)
0:
description: {en-US: "Apple"}
id: "kcContent.questions[3].answerChoices[0]"
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
//this is a Dev Tools view of a "placeholder" instantiated objects
1: TinCan.InteractionComponent // how do I preserve the 'TinCan.InteractionComponent' characteristic when I update this instanced object?
description: {en-US: "pending"}
id: "pending"
__proto__:
LOG_SRC: "InteractionComponent"
asVersion: ƒ (a)
getLangDictionaryValue: ƒ (a,b)
init: ƒ (a)
log: ƒ (a,b)
__proto__: Object
//these are additional "placeholder" objects--all of which have the "TinCan.InteractionComponent" prefix, which is what I'm losing when I try to update elements using the function below
2: TinCan.InteractionComponent {id: "pending", description: {…}}
3: TinCan.InteractionComponent {id: "pending", description: {…}}
4: TinCan.InteractionComponent {id: "pending", description: {…}}
length: 5
__proto__: Array(0)
//This is the function I'm using to update the instantiated object:
function populateStatementChoices(callback){
console.log("Populating statement choices.");
statement.target.definition.choices.forEach(function(item, index) {
function setStatementChoiceID(num){
//this updates the key/values but removes 'TinCan.InteractionComponent' from the object
statement.target.definition.choices[num] = {
id:"kcContent.questions[" choiceQuestionIndex "].answerChoices[" num "]",
description:{"en-US":kcContent.questions[choiceQuestionIndex].answerChoices[num].choiceText},
}
setStatementChoiceID(index);
});
if (typeof callback === 'function'){
callback();
}
};
Сохранение «TinCan.Характеристики InteractionComponent » — это то, что я не могу понять. Надеюсь, кто-то видел это раньше и может указать мне правильное направление. Спасибо за ваше время и внимание; Я ценю это больше, чем вы думаете!
Комментарии:
1. Из того, что я понял из вашего вопроса (это очень грязно, кстати). JSON не имеет дела с функциями. Таким образом, вы потеряете свой прототип или любое свойство функции в вашем объекте. Чего именно вы пытаетесь достичь?
2. Извините за беспорядок и спасибо за помощь. Внутри этого вложенного объекта есть массив (statement.target.definition.choices). У меня есть 5 «заполнителей» с TinCan. характеристики InteractionComponent. Я хочу обновить «идентификатор» и «описание» существующих объектов, не теряя TinCan. характеристики InteractionComponent. Я не уверен, что я делаю (или пренебрегаю) в своей функции, из-за чего мои заполнители теряют значение «TinCan. Характеристики InteractionComponent», когда я обновляю для них ‘id’ и ‘description’.
Ответ №1:
Вы теряете «TinCan.InteractionComponent » потому что вы устанавливаете позицию массива в качестве нового объекта.
statement.target.definition.choices = [ ..., ..., ..., ...]
//your code says, access the array position at number and assign (=) whatever is below to it.
statement.target.definition.choices[num] = {
id:"kcContent.questions[" choiceQuestionIndex "].answerChoices[" num "]",
description:{"en-US":kcContent.questions[choiceQuestionIndex].answerChoices[num].choiceText},
}
Прежде всего, вы должны переписать свою функцию. Вы неправильно используете forEach. Я бы рекомендовал использовать map, потому что он не изменяет массив, но для простоты ваш код можно упростить до:
function populateStatementChoices(callback){
console.log("Populating statement choices.");
statement.target.definition.choices.forEach(function(item, index) {
item.id = "kcContent.questions[" choiceQuestionIndex "].answerChoices[" index "]";
item.description = { "en-US": kcContent.questions[choiceQuestionIndex].answerChoices[index].choiceText};
}
if (typeof callback === 'function'){
callback();
}
};
При этом вы должны быть готовы выполнить обновление без потери других свойств.
Комментарии:
1. Спасибо за помощь! Я впервые использовал forEach (что объясняет некоторую путаницу). Я попробовал более простую функцию, которую вы предложили, и она сохраняет TinCan. InteractionComponent (ура!). К сожалению, теперь у меня, похоже, проблема с закрытием: когда forEach завершает цикл по элементам, устанавливает все из них в item.id и item.description, предназначенный для последнего элемента.
2. Внутренняя функция с параметром [num] была моей попыткой изолировать / сохранить значение index во время вызова функции; это, казалось, решило проблему закрытия.
3. @KevanSizemore Если вам нравится ответ, проголосуйте как за правильный. Вот как вы выражаете благодарность здесь 🙂
4. @KevanSizemore почему вы пытаетесь сохранить индекс? Есть ли что-нибудь еще, чего я не вижу?
5. Размышляя над вашими комментариями и предложениями, я в конечном итоге вернулся назад и спросил себя, почему я не мог заполнить массив перед созданием экземпляра объекта. Как оказалось, это был гораздо более простой подход, и он устранил проблемы, с которыми я сталкивался при потере TinCan. Проблемы с InteractionComponent или закрытием, из-за которых в каждый элемент массива было записано самое последнее значение итерации ‘id’ и ‘description’. Иногда чем проще, тем лучше. Спасибо @iwduarte! Я ценю помощь, и вы научили меня некоторым новым вещам. Всего вам наилучшего.