Я анализирую источник данных и хочу заполнить объект в JS, чтобы закончить что-то вроде этого:

data = {
    "USA":
        {"NY":{"active":5,"inactive":2}},
        {"WA":{"active":16,"inactive":11}},
    "Canada":
        {"NY":{"active":5,"inactive":2}}
}

Сначала я не знаю количество стран или штатов, для которых я получу данные. Итак, я начинаю так:

var data = {}

Затем попробуйте заполнить данные следующим образом:

data["USA"]["NY"]["active"] = data["USA"]["NY"]["active"]++;

Но это не работает.

3
Kashif 7 Янв 2017 в 16:25

4 ответа

Лучший ответ

Вы не можете создавать свойства объекта таким образом на лету. Итак, вы правильно создаете объект данных:

var data = {}

Но следующая строка неверна, потому что:

data["USA"] в данный момент не определен, поэтому вы не можете получить доступ к ["NY"] из undefined, что вызовет исключение. Таким образом, вам нужно не только инициализировать корневой data объект, но и инициализировать объект для каждого свойства этого объекта.

Вы можете сделать это буквально:

if(!data["USA"]) 
    data["USA"] = {};

Или используя оператор ||, который назначит data["USA"] один и тот же объект, если он существует (так что в принципе он ничего не сделает), или создаст новый:

data["USA"] = data["USA"] || {};

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

data["USA"] = data["USA"] || {};
data["USA"]["NY"] = data["USA"]["NY"] || {};
data["USA"]["NY"]["active"] = data["USA"]["NY"]["active"] || 0; 

После этого ваша объектная структура готова, просто имейте в виду, что ++ является оператором, который возвращает число, а после этого добавляет один к этому числу.

Так:

data["USA"]["NY"]["active"] = data["USA"]["NY"]["active"]++;

Не будет менять номер, вы должны сделать либо:

data["USA"]["NY"]["active"]++;

Или же:

data["USA"]["NY"]["active"] = data["USA"]["NY"]["active"]+1;
1
alek kowalczyk 7 Янв 2017 в 13:35

Вы можете создать свою собственную функцию, используя reduce(), которая может принимать строку как ключи вложенного объекта и создавать эту глубокую структуру объекта.

var data = {}

function add(str) {
  var arr = str.split('.')
  return arr.reduce(function(r, e, i) {
    return arr.length - 1 != i ? r[e] || (r[e] = {}) : r[e] = (r[e] || 0) + 1
  }, data)
}

add('USA.NY.active')
add('USA.NY.active')
add('USA.NY.inactive')
add('Canada.NY.active')
console.log(data)
0
Nenad Vracar 7 Янв 2017 в 13:39

Для каждого уровня объекта требуется проверка и, если она не установлена, то взять объект по умолчанию или для номера ноль.

var data = {};

data["USA"] = data["USA"] || {};
data["USA"]["NY"] = data["USA"]["NY"] || {};
data["USA"]["NY"]["active"] = data["USA"]["NY"]["active"] || 0;
data["USA"]["NY"]["active"]++;

console.log(data);

Лучше всего использовать функцию для проверки и создания объекта по умолчанию

function getValue(o, path) {
    return path.reduce(function (o, k) {
        return (o || {})[k];
    }, o);
}

function setValue(object, path, value) {
    var way = path.slice(),
        last = way.pop();

    way.reduce(function (r, a) {
        return r[a] = r[a] || {};
    }, object)[last] = value;
}

function increment(object, path, value) {
    setValue(data, path, (getValue(data, path) || 0 ) + (value || 1));
}

var data = {};
increment(data, ['USA', 'NY', 'active'], 1);

console.log(data);
2
Nina Scholz 7 Янв 2017 в 13:39
data["USA"]["NY"]["active"] = data["USA"]["NY"]["active"]++;

Вы:

  1. принимая значение data["USA"]["NY"]["active"] (которое равно 2)
  2. увеличение data["USA"]["NY"]["active"] (так что теперь 3)
  3. присваивая значение, которое вы взяли (2), data["USA"]["NY"]["active"] (эффективно обращая эффект предыдущего шага)

Если вы хотите увеличить значение, сделайте следующее:

data["USA"]["NY"]["active"]++;

... только это, и ничего кроме этого.

0
Quentin 7 Янв 2017 в 13:33