[removed] how to dynamically create nested objects

2019-01-03 23:06发布

I hope someone can help me with this Javascript.

I have an Object called "Settings" and I would like to write a function that adds new settings to that object.

The new setting's name and value are provided as strings. The string giving the setting's name is then split by the underscores into an array. The new setting should get added to the existing "Settings" object by creating new nested objects with the names given by each part of the array, except the last part which should be a string giving the setting's value. I should then be able to refer to the setting and e.g. alert its value. I can do this in a static way like this...

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);

... the part that creates the nested objects is doing this ...

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

However, as the number of parts that make up the setting name can vary, e.g. a newSettingName could be "Modules_Floorplan_Image_Src", I'd like to do this dynamically using a function such as...

createSetting (newSettingNameArray, newSettingValue);

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

Can anyone help me work out how to do this dynamically?

I presume there has to be a for...loop in there to itterate through the array, but I haven't been able to work out a way to create the nested objects.

If you've got this far thanks very much for taking the time to read even if you can't help.

17条回答
贪生不怕死
2楼-- · 2019-01-03 23:41

I think, this is shorter:

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];
}
查看更多
家丑人穷心不美
3楼-- · 2019-01-03 23:41

I found @jlgrall's answer was great but after simplifying it, it didn't work in Chrome. Here's my fixed should anyone want a lite version:

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);

I hope this is useful and relevant. Sorry, I've just smashed this example out...

查看更多
Bombasti
4楼-- · 2019-01-03 23:43

Here is a simple tweak to jlgrall's answer that allows setting distinct values on each element in the nested hierarchy:

var createNestedObject = function( base, names, values ) {
    for( var i in names ) base = base[ names[i] ] = base[ names[i] ] || (values[i] || {});
};

Hope it helps.

查看更多
Anthone
5楼-- · 2019-01-03 23:43

Here is a functional solution to dynamically create nested objects.

const nest = (path, obj) => {
  const reversedPath = path.split('.').reverse();

  const iter = ([head, ...tail], obj) => {
    if (!head) {
      return obj;
    }
    const newObj = {[head]: {...obj}};
    return iter(tail, newObj);
  }
  return iter(reversedPath, obj);
}

Example:

const data = {prop: 'someData'};
const path = 'a.deep.path';
const result = nest(path, data);
console.log(JSON.stringify(result));
// {"a":{"deep":{"path":{"prop":"someData"}}}}
查看更多
Fickle 薄情
6楼-- · 2019-01-03 23:43

I love this ES6 immutable way to set certain value on nested field:

const setValueToField = (fields, value) => {
  const reducer = (acc, item, index, arr) => ({ [item]: index + 1 < arr.length ? acc : value });
  return fields.reduceRight(reducer, {});
};

And then use it with creating your target object.

const targetObject = setValueToField(['one', 'two', 'three'], 'nice');
console.log(targetObject); // Output: { one: { two: { three: 'nice' } } }
查看更多
混吃等死
7楼-- · 2019-01-03 23:44

Set Nested Data:

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"}}}

Get Nested Data:

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
查看更多
登录 后发表回答