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

Easy way to set javascript object multilevel property?

本文关键字:简单 方法 属性 多级 javascript 对象 设置      更新时间:2024-03-29

我正在尝试创建一个类似的javascript对象

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

但我得到了一个类似allUserExpiry[aData.userId]未定义的错误。

有没有办法,我可以设置多级JS对象键?或者我应该先做allUserExpiry[aData.userId]={},然后再做allUserExpiry[aData.userId][aData.courseId]={},这很重要吗?

请让我知道是否有任何实用功能可用于相同。

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

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

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

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

只需使用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

或者你可以这样做:

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

这种方法有很多弱点,但为了好玩…:)

为什么不直接这么做呢?

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

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

将该对象存储在CCD_ 8中。

工作原理:

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

这依赖于使用引用,因此如果您希望您的代码由其他人维护,则不会立即清楚它是如何工作的,老实说,可能应该避免,但它至少可以工作。

您还可以使用以下方法创建初始结构:

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

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

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

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

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

它将返回布尔值。

另一个使用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));

假设我们的对象是

const data = {
  //some other data
  userInfo: {},
};

首先,定义对象的一个新属性

data.userInfo.vehicle = {};

然后简单地

data.userInfo.vehicle.vehicleType = state.userInfo.vehicleType;