JavaScript字符串转嵌套对象

7
我有一个空对象和一个字符串:
var obj = {};
var str = "a.b.c";

有没有办法可以将这个转换为
obj = { a: { b: { c: { } } } }

我有点理解不了这个问题,甚至不确定是否可能实现。


2
你的情境和最终目标是什么?我怀疑有比尝试做这样的事情更好的方法来实现你的终极目标。 - Darin Dimitrov
这是一个面试问题吗? - Yevgeny Simkin
可能是以下内容的重复:从“命名空间”字符串构建对象层次结构 - Felix Kling
@Felix - 是的,重复了,但那里给出的答案是一个好答案吗? - mplungjan
哈哈,这不是面试问题,但是哇,如果我面试任何人,我可能会用这个问题。我有一个带有与每个输入字段相关联的数据的表单,它“看起来像这样”,我需要构建一个JSON对象返回到服务器。这里有很好的建议,明天回到工作时会尝试一些。 - user977433
显示剩余2条评论
5个回答

10
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/缩写(数组存储不必要):

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


1
这是一个非常聪明和优雅简洁的解决方案。我原本的代码与此非常接近,但一开始没有设置 tmp = obj,导致了问题。感谢您的帮助! - user977433
@user977433:我怀疑在循环内部,你可以将其压缩为tmp = tmp[arr[i]] = {}并且去掉花括号。 - vol7ron
@vol7ron,你的意思是和我回答的那个一模一样吗? - David Hellsing
@vol7ron,无论如何,你的答案几乎和我的一样,只是更冗长。你甚至使用了相同的变量名。而且看看时间,它发布的时间正好比我晚30分钟。如果你问我,这有点违背了SO的整个目的... - David Hellsing
@David:如果你因为恶意而扣分,那么这就有点违背了 SO 的初衷,如果你问我的话... - vol7ron
显示剩余2条评论

3
这是来自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(/\./)))

编辑:删除了“字符串输入”版本,因为它仅适用于命名空间中的单个字母子部分,例如问题中给出的一个(a.b.c),这通常不是情况。


0

给你:

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

示例


这是一个非常有趣的方法。但我很好奇,相较于这个或者上面那个被点赞的方法,是什么让我的解决方案(它更易读)变得不如此有用呢?难道代码的清晰简洁不值得一提吗? - Yevgeny Simkin
@Dr.Dredel,我听到你的声音了,但是在SO社区中,对于JavaScript中的eval()存在普遍的厌恶情绪。实际上,由于您控制着传递给eval()的代码,因此在您的解决方案中使用它的主要缺点是性能受到影响。顺便说一下:https://dev59.com/z3VC5IYBdhLWcg3wvT1a - Jonathan M
1
@Johathan M. 谢谢!我点击了那个链接,本以为会被告知使用 eval 是一个彻头彻尾的错误,但它是一个非常冷静和理性的检查,实际上清楚地说明使用 eval 并没有太多负担,应该尽可能地像我一样使用它(如果可能的话)来减少代码混乱。正如我所说,我的解决方案基本上只是一个 hack,而且它是对一个问题的第一个答案,这个问题的目的仍然让我困惑。总的来说,我发现 SOers 经常小气并渴望对那些可以轻松忽略的事情进行投票。 - Yevgeny Simkin

0
这是我的看法:
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: {} } } }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接