[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:45

Another recursive solution:

var nest = function(obj, keys, v) {
    if (keys.length === 1) {
      obj[keys[0]] = v;
    } else {
      var key = keys.shift();
      obj[key] = nest(typeof obj[key] === 'undefined' ? {} : obj[key], keys, v);
    }

    return obj;
};

Example usage:

var dog = {bark: {sound: 'bark!'}};
nest(dog, ['bark', 'loudness'], 66);
nest(dog, ['woff', 'sound'], 'woff!');
console.log(dog); // {bark: {loudness: 66, sound: "bark!"}, woff: {sound: "woff!"}}
查看更多
【Aperson】
3楼-- · 2019-01-03 23:47

try using recursive function:

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);
  }
}
查看更多
ら.Afraid
4楼-- · 2019-01-03 23:47

A snippet for those who need to create a nested objects with support of array keys to set a value to the end of path. Path is the string like: modal.product.action.review.2.write.survey.data. Based on jlgrall version.

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]] || {};
        }
    }
};
查看更多
何必那么认真
5楼-- · 2019-01-03 23:48

Using ES6 is shorten. Set your path into an array. first, you have to reverse the array, to start filling the object.

let obj = ['a','b','c'] // {a:{b:{c:{}}}
obj.reverse();

const nestedObject = obj.reduce((prev, current) => (
    {[current]:{...prev}}
), {});
查看更多
叛逆
6楼-- · 2019-01-03 23:48

Eval is probably overkill but the result is simple to visualize, with no nested loops or recursion.

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

Basically you are progressively writing a string "obj['one']= {}", "obj['one']['two']"= {} and evaling it;

查看更多
萌系小妹纸
7楼-- · 2019-01-03 23:49

Appreciate that this question is mega old! But after coming across a need to do something like this in node, I made a module and published it to npm. Nestob

var nestob = require('nestob');

//Create a new nestable object - instead of the standard js object ({})
var newNested = new nestob.Nestable();

//Set nested object properties without having to create the objects first!
newNested.setNested('biscuits.oblong.marmaduke', 'cheese');
newNested.setNested(['orange', 'tartan', 'pipedream'], { poppers: 'astray', numbers: [123,456,789]});

console.log(newNested, newNested.orange.tartan.pipedream);
//{ biscuits: { oblong: { marmaduke: 'cheese' } },
  orange: { tartan: { pipedream: [Object] } } } { poppers: 'astray', numbers: [ 123, 456, 789 ] }

//Get nested object properties without having to worry about whether the objects exist
//Pass in a default value to be returned if desired
console.log(newNested.getNested('generic.yoghurt.asguard', 'autodrome'));
//autodrome

//You can also pass in an array containing the object keys
console.log(newNested.getNested(['chosp', 'umbridge', 'dollar'], 'symbols'));
//symbols

//You can also use nestob to modify objects not created using nestob
var normalObj = {};

nestob.setNested(normalObj, 'running.out.of', 'words');

console.log(normalObj);
//{ running: { out: { of: 'words' } } }

console.log(nestob.getNested(normalObj, 'random.things', 'indigo'));
//indigo
console.log(nestob.getNested(normalObj, 'improbable.apricots'));
//false
查看更多
登录 后发表回答