Как создать свойство 2-го уровня для объекта JS с помощью скобок

Вот сделка. Я начинаю с объектного литерала.

var prepObj = {};

Затем я буду выполнять foreach, добавляя свойства к этому объекту. В принципе, в итоге это будет выглядеть примерно так (в более крупном масштабе).

{
    34 : {
        prop1: myvalue,
        prop2: myvalue,
    }
    87 : {
        prop1: myvalue,
        prop2: myvalue,
    }
    102 : {
        prop1: myvalue,
        prop2: myvalue,
    }
}

На протяжении цикла я буду находить значение для определенного свойства определенного индекса (например, prop1 из 87) и создавать его для объекта.

Итак, перед циклом я начинаю с пустого объекта.

Затем во время цикла я подумал, что могу сделать:

var index_id = 87;
var which_prop = "prop1";
var prop_value = "This is a value.";

prepObj[index_id][which_prop] = prop_value;

но когда я пытаюсь это сделать, я получаю сообщение об ошибке:

Uncaught TypeError: Cannot set property 'prop1' of undefined

Что я делаю не так?


person Pete    schedule 04.12.2013    source источник


Ответы (2)


JavaScript не поддерживает автовивикацию. Вы должны определить prepObj[index_id] = {} перед определением prepObj[index_id][which_prop] = prop_value.

Это связано с тем, что prepObj[index_id] изначально не определено. Таким образом, вы пытаетесь установить свойство prop1 для prepObj[index_id], которое равно undefined. Вы избегаете этого, делая prepObj[index_id] некоторое определенное значение.

Если вы беспокоитесь о том, чтобы каждый раз затирать prepObj[index_id] новым объектом, вы можете проверить, что значение уже установлено:

  • index_id in prepObj — это проверяет, что в prepObj уже есть запись, ключ которой является значением index_id

  • typeof prepObj[index_id] != "undefined" — проверяет, не равно ли значение prepObj[index_id] undefined

  • prepObj[index_id] || {} - оценивается как prepObj[index_id], если это не ложное значение (например, undefined); в противном случае он оценивается как новый объект

person apsillers    schedule 04.12.2013
comment
Ох! Ответ И новый словарный запас. Мне это нравится. Как я могу сначала проверить, был ли создан экземпляр prepObj[index_id] (чтобы избежать его перезаписи)? (Задается до того, как ответ был отредактирован, чтобы включить предложенный ответ). - person Pete; 04.12.2013
comment
@Пит prepObj[index_id] = prepObj[index_id] || {}; - person jbabey; 04.12.2013
comment
Есть ли какое-то преимущество в тестировании ОБА index_id в prepObj и typeof prepObj[index_id] != undefined? - person Pete; 04.12.2013
comment
@ Пит Может быть? Неудачный тест in обязательно означает, что значение равно undefined. Однако пройденный тест in может означать, что ключ имеет значение undefined или любое другое значение — это просто означает, что ключ существует. Если вы явно не назначаете свойства undefined, все эти тесты, вероятно, будут работать для вашего простого случая. - person apsillers; 04.12.2013
comment
Итак, будет ли самый элегантный способ написать это: prepObj[index_id] = (index_id в prepObj)? prepObj[index_id] : {}; - person Pete; 04.12.2013
comment
Вероятно, наиболее JS-идоматический способ — это именно то, что jbabey написал с использованием оператора ИЛИ: prepObj[index_id] = prepObj[index_id] || {}; Это прекрасно работает, пока вы уверены, что prepObj[index_id] никогда не будет преднамеренно ложным значением, таким как false, 0 или "". Если вы знаете, что это будет только объект или undefined, это именно то, что вам нужно. В остальном предложенный вами код тоже работает хорошо. - person apsillers; 04.12.2013

Попробуй это:

prepObj[index_id] = {};
prepObj[index_id][which_prop] = prop_value;
person Mike Thomsen    schedule 04.12.2013
comment
Пожалуйста, объясните проблему и ваше решение, а не просто напишите, попробуйте это. - person Felix Kling; 04.12.2013