【问题标题】:Javascript nested objects from string来自字符串的Javascript嵌套对象
【发布时间】:2011-11-30 05:48:36
【问题描述】:

我有一个空对象和一个字符串:

var obj = {};
var str = "a.b.c";

有什么办法可以把它变成

obj = { a: { b: { c: { } } } }

我无法完全理解这一点,我什至不确定这是否可能。

【问题讨论】:

  • 你的方案和最终目标是什么?我怀疑有更好的方法来实现你的最终目标,而不是尝试做这样的事情。
  • 这是一个面试题吗?
  • YUI 中有类似的东西来创建对象。我看看能不能找到。
  • 使用 JavaScript 几乎一切皆有可能;有些事情的效率要低得多......

标签: javascript jquery string object split


【解决方案1】:
var obj = {};
var str = "a.b.c";
var arr = str.split('.');
var tmp = obj;

for (var i=0,n=arr.length; i<n; i++){
   tmp[arr[i]]={};
   tmp = tmp[arr[i]];
}

ES6:

let str = "a.b.c",
    arr = str.split('.'),
    obj, o = obj = {};

arr.forEach(key=>{o=o[key]={}});

console.log(obj);

ES6/Reduced(不需要数组存储):

let str = "a.b.c", obj, o = obj = {};

str.split('.').forEach(key=>o=o[key]={});

console.log(obj);

ES6/Array.prototype.reduce:

let str = "a.b.c", last;

let obj = str.split('.').reduce((o, val) => {
  if (typeof last == 'object')
    last = last[val] = {};
  else
    last = o[val] = {};

  return o;
}, {});

console.log(obj);

【讨论】:

  • 如此出色且优雅简单的解决方案。我所拥有的非常接近这一点,但我最初并没有设置 tmp = obj 从而导致了这个问题。感谢您的帮助!
  • @user977433:我怀疑在循环内部您可以将其压缩为 tmp = tmp[arr[i]] = {} 并去掉花括号。
  • @vol7ron 你的意思和我比你早 30 分钟的回答一模一样?
  • @vol7ron 不管怎样,你的答案几乎和我的一样,除了更冗长。你甚至使用了相同的变量名。检查时间,它是在 30 分钟后发布的。如果你问我,有点违背 SO 的全部目的......
  • @David:如果你问我,你出于恶意而扣分作为答案的事实有点违背 SO 的全部目的......
【解决方案2】:

这是来自 yui2 yahoo.js 文件。

YAHOO.namespace = function() {
  var a=arguments, o=null, i, j, d;
  for (i=0; i<a.length; i=i+1) {
      d=(""+a[i]).split(".");
      o=YAHOO;

      // YAHOO is implied, so it is ignored if it is included
      for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; j=j+1) {
          o[d[j]]=o[d[j]] || {};
          o=o[d[j]];
      }
  }

  return o;
};

查看文档来源。

https://github.com/yui/yui2/blob/master/src/yahoo/js/YAHOO.js

【讨论】:

    【解决方案3】:

    此递归函数返回所需对象的字符串表示形式

    //Usage: getObjectAsString('a.b.c'.split(/\./))
    function getObjectAsString (array){
       return !array.length ? '{}' 
                 : '{"' + array[0] + '":' + getObjectAsString (array.slice(1)) + '}';
    }
    

    现在您可以使用

    将 getObjectAsString 的输出转换为对象
    JSON.parse(getObjectAsString('a.b.c'.split(/\./)))
    

    编辑:删除了“输入为字符串”版本,因为它仅适用于命名空间中的单个字母子部分,例如问题 (abc) 中给出的子部分,但通常情况并非如此。

    【讨论】:

      【解决方案4】:

      给你:

      var string = "a.b.c",
         array = string.split('.');
      JSON.parse("{\"" + array.join('": {\"') + "\": {" +array.map(function () {return '}'}).join('') + "}")
      

      Example

      【讨论】:

      • 这是一个非常有趣的方法。不过我很好奇,是什么让我的解决方案(它更容易阅读)比这个或上面的那个更有用。对于代码的清晰性和简洁性,没有什么要说的吗?
      • @Dr.Dredel,我听到了,伙计,但在 SO'ers 中,JavaScript 中的eval() 普遍存在反感。确实,由于您正在控制提供给 eval() 的代码,因此在您的解决方案中使用它的主要缺点是对性能的影响。仅供参考:stackoverflow.com/questions/197769/…
      • @Johathan M. 谢谢!我点击了那个链接,希望被告知我是一个使用 eval 的彻头彻尾的笨蛋,但这是一个非常清醒和理性的检查,它实际上清楚地表明使用 eval 并没有那么多任务,应该使用得漂亮和我使用的完全一样(如果可能的话,以减少代码混乱)。正如我所说,我的解决方案基本上只是一个 hack,它是对一个问题的第一个答案,这个问题的目的仍然让我难以捉摸。总的来说,我发现 SOers 经常是吝啬的,并且渴望对很容易被忽略的事情投反对票。
      【解决方案5】:

      这是我的看法:

      function ensureKeys(str, obj) {
          for(var parts = str.split('.'), i=0, l=parts.length, cache=obj; i<l; i++) {
              if(!cache[parts[i]]) { 
                  cache[parts[i]] = {};
              }
              cache = cache[parts[i]];
          }
      
          return obj;
      }
      
      var obj = {};
      ensureKeys('a.b.c', obj);
      // obj = { a: { b: { c: {} } } }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-22
        相关资源
        最近更新 更多