设置javascript对象多级属性的简便方法?

时间:2013-12-06 12:43:02

标签: javascript json object key-value

我正在尝试创建一个像

这样的javascript对象
var allUserExpiry={};
allUserExpiry[aData.userId][aData.courseId][aData.uscId] = aData;

但我收到的错误如allUserExpiry[aData.userId]未定义。

有没有办法,我可以设置多级JS-Object键?或者重要的是我应该allUserExpiry[aData.userId]={},然后allUserExpiry[aData.userId][aData.courseId]={}

如果有相同的实用功能,请告诉我。

10 个答案:

答案 0 :(得分:7)

不,没有办法设置“多级键”。在尝试向其添加属性之前,需要初始化每个对象。

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

答案 1 :(得分:3)

或者你可以这样做:

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

并使用:

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

这种方法有很多不足之处,但为了好玩......:)

答案 2 :(得分:2)

为什么不这样做?

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

答案 3 :(得分:2)

使用ES6中的Computed属性名称,可以执行以下操作:

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

答案 4 :(得分:2)

我在IE9 +以及真正的浏览器中做了一个非常简单但很简单的方法。

鉴于var path = 'aaa.bbb.ccc.ddd.eee';其中path是您打算在对象中创建的内容,var result = {};将创建对象{aaa: {bbb: {ccc: {ddd: {eee: {}}}}}

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

会将对象存储在result

工作原理:

  • split('.')将输入转换为['aaa', 'bbb', 'ccc', 'ddd', 'eee']
  • reduce(function (...) {...}, result)遍历split创建的数组,并且每个条目都会将返回的值传递给下一个。在我们的例子中,我们在将新对象添加到旧对象之后传递新对象。这会创建一个对象链。 reduce会返回您在其中返回的最后一个对象,因此我们必须事先定义result

这依赖于使用引用,因此如果您期望您的代码由其他任何人维护,并且可能应该避免诚实,那么它将不会立即清楚它是如何工作的,但它至少可以工作。

答案 5 :(得分:1)

您还可以使用以下内容创建初始结构:

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

答案 6 :(得分:1)

另一种没有字符串或数组作为参数的方法。

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

但我不会用它:-)这只是为了好玩。 因为我不喜欢太多的智能算法。 (如果属于这一类)

答案 7 :(得分:1)

使用lodash,您可以轻松地执行此操作(节点存在并对该节点进行空检查) ..

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

用法:

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

    };

    var validate;

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

它将返回布尔值。

答案 8 :(得分:1)

只需使用loadash,

ggplot(mat_long, aes(x = col, y = row, fill = as.character(value))) +
   geom_tile(color = "black") +
   scale_fill_manual(values = colors) +
   theme_void()

答案 9 :(得分:1)

使用 reduce 功能的另一种解决方案(感谢Brian K)。

在这里,我们创建了针对一般提议的获取/设置。第一个函数返回任意级别的值。考虑分隔符来分割密钥。该函数返回从键的数组中的最后一个索引引用的值

第二个函数将考虑拆分键的最后一个索引来设置新值

代码:

    function getObjectMultiLevelValue(_array,key,separator){
        key = key.split(separator || '.');
        var _value = JSON.parse(JSON.stringify(_array));

        for(var ki in key){
                _value = _value[key[ki]];
        }
        return _value;
    }

    function setObjectMultiLevelValue(_array,key,value,forcemode,separator){
        key.split(separator || '.').reduce(function(prev, currKey, currIndex,keysArr) {
            var newObj = {};
            if(prev[currKey] && !forcemode){
                newObj = prev[currKey];
            }
            if(keysArr[keysArr.length-1] == currKey){
                newObj = value;
                prev[currKey] = newObj;
            }

            prev[currKey] = newObj;
            return newObj;
        }, _array);
        return _array;
    }

//testing the function
//creating an array
    var _someArray = {a:'a',b:'b',c:{c1:'c1',c2:{c21:'nothing here...'}}};
//a multilevel key to test
    var _key = 'a,a1,a21';
//any value
    var _value = 'new foo in a21 key forcing replace old path';

//here the new value will be inserted even if the path exists (forcemode=true). Using comma separator
    setObjectMultiLevelValue(_someArray,_key,_value,true,',');
    console.log('_someArray:');
    console.log(JSON.stringify(_someArray));

//inserting another value in another key... using default separator
    _key = 'c.c2.c21';
    _value = 'new foo in c21 key';
    setObjectMultiLevelValue(_someArray,_key,_value);
    console.log('_someArray:');
    console.log(JSON.stringify(_someArray));

//recovering the saved value with different separators
    _key = 'a,a1,a21';
    console.log(getObjectMultiLevelValue(_someArray,_key,','));
    _key = 'c.c2.c21';
    console.log(getObjectMultiLevelValue(_someArray,_key));