Easy way to set javascript object multilevel prope

2019-04-14 22:53发布

问题:

I am trying to create a javascript object like

var allUserExpiry={};
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;

But I am getting an error like allUserExpiry[aData.userId] undefined.

Is there a way, whereby I can set multi-level JS-Object keys? or is it important that I should go by doing allUserExpiry[aData.userId]={}, then allUserExpiry[aData.userId][aData.courseId]={} ?

Please let me know if there are any utility functions available for the same.

回答1:

No, there is no way to set "multilevel keys". You need to initialize each object before trying to add properties to it.

var allUserExpiry = {};
allUserExpiry[aData.userId] = {}
allUserExpiry[aData.userId][aData.courseId] = {}
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;


回答2:

Or you can do it:

function setByPath(obj, path, value) {
    var parts = path.split('.');
    var o = obj;
    if (parts.length > 1) {
      for (var i = 0; i < parts.length - 1; i++) {
          if (!o[parts[i]])
              o[parts[i]] = {};
          o = o[parts[i]];
      }
    }

    o[parts[parts.length - 1]] = value;
}

And use:

setByPath(obj, 'path.path2.path', someValue);

This approach has many weak places, but for fun... :)



回答3:

Why not just do this?

var allUserExpiry={};
allUserExpiry[aData.userId] = {aData.courseId: {aData.uscId: aData}};


回答4:

Using Computed property names from ES6, it is possible to do:

var allUserExpiry = {
    [aData.userId] = {
        [aData.courseId]: {
            [aData.uscId]: aData
        }
    }
};

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names



回答5:

I have a pretty hacky but short way of doing it in IE9+ as well as real browsers.

Given var path = 'aaa.bbb.ccc.ddd.eee'; where path is what your intending to make into an object and var result = {}; will will create the object {aaa: {bbb: {ccc: {ddd: {eee: {}}}}}

result = {}
path.split('.').reduce(function(prev, e) {
    var newObj = {};
    prev[e] = newObj;
    return newObj;
}, result);

will store the object in result.

How it works:

  • split('.') converts the input into ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
  • reduce(function (...) {...}, result) runs through the array created by split, and for each entry will pass along a returned value to the next one. In our case we pass the new object through after adding the new object to the old one. This creates a chain of objects. reduce returns the last object you return inside of it, so we have to defined result beforehand.

This relies on using references so it won't be immediately clear how it works if you're expecting your code to be maintained by anyone else and should probably be avoided to be honest, but it works at least.



回答6:

You can also use the following to create the initial structure:

var x = function(obj, keys) {
    if (!obj) return;

    var i, t;
    for (i = 0; i < keys.length; i++) {
        if (!t) {
            t = obj[keys[i]] = {};
        } else {
            t[keys[i]] = {};
            t = t[keys[i]];
        }
    }
};

var a = {}; 
x(a, ['A', 'B', 'C', 'D', 'E', 'F']);


回答7:

Another approach without strings or array as argument.

function fillObject() {
  var o = arguments[0];
  for(var i = 1; i < arguments.length-1; i++) {
    if(!o.hasOwnProperty(arguments[i])) {
      o[arguments[i]] = {};
    }
    if(i < arguments.length-2) {
      o = o[arguments[i]];
    }else {
      o[arguments[i]] = arguments[i+1]
    }
  }
}

var myObj = {"foo":{}};

fillObject(myObj,"back","to","the","future",2);

console.log(JSON.stringify(myObj));
// {"foo":{},"back":{"to":{"the":{"future":2}}}}

But I wouldn't use it :-) It's just for fun. Because I don't like too much intelligent algorithm. (If it was in this category)



回答8:

Using lodash you can do this easily (node exists and empty check for that node)..

var lodash = require('lodash-contrib');

function invalidateRequest(obj, param) {
    var valid = true;

    param.forEach(function(val) {
        if(!lodash.hasPath(obj, val)) {
            valid = false;
        } else {
            if(lodash.getPath(obj, val) == null || lodash.getPath(obj, val) == undefined || lodash.getPath(obj, val) == '') {
                valid = false;
            }
        }
    });
    return valid;
}

Usage:

leaveDetails = {
              "startDay": 1414998000000,
              "endDay": 1415084400000,
              "test": { "test1" : 1234 }

    };

    var validate;

    validate = invalidateRequest(leaveDetails, ['startDay', 'endDay', 'test.test1']);

it will return boolean.



回答9:

Simply use loadash,

let object = {};
let property = "a.b.c";
let value = 1;
_.set(object, property, value); // sets property based on path
let value = _.get(object, property, default); // gets property based on path