Javascript: как динамически создавать вложенные объекты, используя имена объектов, заданные массивом - PullRequest
53 голосов
/ 30 марта 2011

Я надеюсь, что кто-то может помочь мне с этим Javascript.

У меня есть объект под названием «Настройки», и я хотел бы написать функцию, которая добавляет новые настройки для этого объекта.

имя и значение новой настройки предоставляются в виде строк.Строка, дающая имя параметра, затем разделяется подчеркиванием на массив.Новый параметр должен быть добавлен к существующему объекту «Настройки» путем создания новых вложенных объектов с именами, заданными каждой частью массива, кроме последней части, которая должна быть строкой, дающей значение параметра.Затем я должен иметь возможность обратиться к настройке и, например, предупредить ее значение.Я могу сделать это статическим способом, как это ...

var Settings = {};
var newSettingName = "Modules_Video_Plugin";
var newSettingValue = "JWPlayer";
var newSettingNameArray = newSettingName.split("_");

Settings[newSettingNameArray[0]] = {};
Settings[newSettingNameArray[0]][newSettingNameArray[1]] = {};
Settings[newSettingNameArray[0]][newSettingNameArray[1]][newSettingNameArray[2]] = newSettingValue;

alert(Settings.Modules.Mediaplayers.Video.Plugin);

... часть, которая создает вложенные объекты, делает это ...

Settings["Modules"] = {};
Settings["Modules"]["Video"] = {};
Settings["Modules"]["Video"]["Plugin"] = "JWPlayer";

Однако, какколичество частей, составляющих имя настройки, может варьироваться, например, newSettingName может быть «Modules_Floorplan_Image_Src», я хотел бы сделать это динамически, используя такую ​​функцию, как ...

createSetting (newSettingNameArray, newSettingValue);

function createSetting(setting, value) {
    // code to create new setting goes here
}

Может кто-нибудь помочьмне решить, как сделать это динамически?

Я предполагаю, что должен быть цикл for ... для перехода через массив, но я не смог найти способ создатьвложенные объекты.

Если вы зашли так далеко, большое спасибо за то, что нашли время прочитать, даже если вы не можете помочь.

Ответы [ 17 ]

0 голосов
/ 19 января 2017

Eval, вероятно, излишний, но результат прост для визуализации, без вложенных циклов или рекурсии.

 function buildDir(obj, path){
   var paths = path.split('_');
   var final = paths.pop();
   for (let i = 1; i <= paths.length; i++) {
     var key = "obj['" + paths.slice(0, i).join("']['") + "']"
     console.log(key)
     eval(`${key} = {}`)
   }
   eval(`${key} = '${final}'`)
   return obj
 }

 var newSettingName = "Modules_Video_Plugin_JWPlayer";
 var Settings = buildDir( {}, newSettingName );

По сути, вы постепенно пишете строку "obj['one']= {}", "obj['one']['two']"= {} и оцениваете ее;

0 голосов
/ 30 марта 2011

Я думаю, это короче:

Settings = {};
newSettingName = "Modules_Floorplan_Image_Src";
newSettingValue = "JWPlayer";
newSettingNameArray = newSettingName.split("_");

a = Settings;
for (var i = 0 in newSettingNameArray) {
    var x = newSettingNameArray[i];
    a[x] = i == newSettingNameArray.length-1 ? newSettingValue : {};
    a = a[x];
}
0 голосов
/ 21 апреля 2016

Установить вложенные данные:

function setNestedData(root, path, value) {
  var paths = path.split('.');
  var last_index = paths.length - 1;
  paths.forEach(function(key, index) {
    if (!(key in root)) root[key] = {};
    if (index==last_index) root[key] = value;
    root = root[key];
  });
  return root;
}

var obj = {'existing': 'value'};
setNestedData(obj, 'animal.fish.pet', 'derp');
setNestedData(obj, 'animal.cat.pet', 'musubi');
console.log(JSON.stringify(obj));
// {"existing":"value","animal":{"fish":{"pet":"derp"},"cat":{"pet":"musubi"}}}

Получить вложенные данные:

function getNestedData(obj, path) {
  var index = function(obj, i) { return obj && obj[i]; };
  return path.split('.').reduce(index, obj);
}
getNestedData(obj, 'animal.cat.pet')
// "musubi"
getNestedData(obj, 'animal.dog.pet')
// undefined
0 голосов
/ 06 января 2016

Фрагмент для тех, кому необходимо создать вложенные объекты с поддержкой ключей массива, чтобы установить значение в конец пути.Путь это строка типа: modal.product.action.review.2.write.survey.data.Основано на версии jlgrall.

var updateStateQuery = function(state, path, value) {
    var names = path.split('.');
    for (var i = 0, len = names.length; i < len; i++) {
        if (i == (len - 1)) {
            state = state[names[i]] = state[names[i]] || value;
        }
        else if (parseInt(names[i+1]) >= 0) {
            state = state[names[i]] = state[names[i]] || [];
        }
        else {
            state = state[names[i]] = state[names[i]] || {};
        }
    }
};
0 голосов
/ 30 марта 2011

попробуйте использовать рекурсивную функцию:

function createSetting(setting, value, index) {
  if (typeof index !== 'number') {
    index = 0;
  }

  if (index+1 == setting.length ) {
    settings[setting[index]] = value;
  }
  else {
    settings[setting[index]] = {};
    createSetting(setting, value, ++index);
  }
}
0 голосов
/ 27 мая 2015

Вы можете определить свои собственные методы объекта;также я использую подчеркивание для краткости:

var _ = require('underscore');

// a fast get method for object, by specifying an address with depth
Object.prototype.pick = function(addr) {
    if (!_.isArray(addr)) return this[addr]; // if isn't array, just get normally
    var tmpo = this;
    while (i = addr.shift())
        tmpo = tmpo[i];
    return tmpo;
};
// a fast set method for object, put value at obj[addr]
Object.prototype.put = function(addr, val) {
    if (!_.isArray(addr)) this[addr] = val; // if isn't array, just set normally
    this.pick(_.initial(addr))[_.last(addr)] = val;
};

Пример использования:

var obj = { 
           'foo': {
                   'bar': 0 }}

obj.pick('foo'); // returns { bar: 0 }
obj.pick(['foo','bar']); // returns 0
obj.put(['foo', 'bar'], -1) // obj becomes {'foo': {'bar': -1}}
0 голосов
/ 28 января 2015

Я нашел ответ @ jlgrall великолепным, но после упрощения он не работал в Chrome.Вот мое исправление, если кому-то нужна облегченная версия:

var callback = 'fn.item1.item2.callbackfunction',
    cb = callback.split('.'),
    baseObj = window;

function createNestedObject(base, items){
    $.each(items, function(i, v){
        base = base[v] = (base[v] || {});
    });
}

callbackFunction = createNestedObject(baseObj, cb);

console.log(callbackFunction);

Надеюсь, это полезно и актуально.Извините, я только что разбил этот пример ...

...