【问题标题】:Easy way to set javascript object multilevel property?设置javascript对象多级属性的简单方法?
【发布时间】:2013-12-23 19:46:00
【问题描述】:

我正在尝试创建一个类似

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

但我收到类似allUserExpiry[aData.userId] undefined 的错误。

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

如果有任何可用的实用功能,请告诉我。

【问题讨论】:

    标签: javascript json object key-value


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      或者你可以这样做:

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

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

      【讨论】:

      • 请问这种方法有什么问题,它的弱点是什么?
      • @user3034931,当然,它不利于代码分析(和代码维护)和代码压缩(使用属性重命名时,导致该字符串不会被更改)。
      • 这不是“简单的方法”。
      • @IgorParra,哈哈,请不要忘记对问题的所有答案发表相同的评论 :)
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

        但我不会使用它 :-) 这只是为了好玩。 因为我不太喜欢智能算法。 (如果它在这个类别中)

        【讨论】:

          【解决方案5】:

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

          它将返回布尔值。

          【讨论】:

            【解决方案6】:

            为什么不这样做呢?

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

            【讨论】:

            • 答案往往更有助于解释它们的工作原理和原因,以及代码。
            【解决方案7】:

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

            【讨论】:

              【解决方案8】:

              在 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

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

              【讨论】:

              • 也许问这个为时已晚,但不应该是 newObj = prev[e];而不是 prev[e] = newObj; ?
              【解决方案9】:

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

              【讨论】:

              • 应该是响应!
              【解决方案10】:

              另一个使用 reduce 函数的解决方案(感谢Brian K)。

              在这里,我们为一般提议创建了一个 get/set。第一个函数返回任何级别的值。考虑到分隔符,密钥被拆分。该函数返回键数组中最后一个索引所引用的值

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

              代码:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-03-14
                • 2013-04-11
                • 2023-02-24
                • 2016-02-16
                • 2014-11-18
                • 2023-03-31
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多