递归地扩展json对象

时间:2013-11-19 11:11:31

标签: javascript jquery json recursion

我有一个递归的json结构,它包含一些属性和一个包含子节点的节点,它的格式与它需要的格式相同。下面的示例不完整或与我的数据相同,但它显示了粗略的结构。

[{"page":{
    title: "my title 1",
    children: [
        {"page":{
            title: "my title 2",
            children: [ ... ]
        },{"page":{
            title: "my title 3",
            children: [ ... ]
        },{"page":{
            title: "my title 4",
            children: [
                {"page": {
                    title: "my other title",
                    children: [ ... ]
                }]
        },{"page":{
            title: "my title 5",
            children: [ ... ]
        }]
        ... etc

我想扩展该对象,以便每个“页面”对象都获得一组新的属性 - 例如我希望将{score: 5.3, theme:"moody"}添加到每个“页面”,以便它们都获得属性,这样如果我要对json对象进行字符串化,那么每个页面都会添加这些属性。

{"page":{title:"some title", score: 5.3, theme: "moody"}}

有没有办法递归扩展json / object结构,最好是在jQuery中?

1 个答案:

答案 0 :(得分:4)

首先,你拥有的是一系列对象。数组是本机JS对象(实际上是Object的扩充实例)。 JS中没有 JSON对象这样的东西,因为JSON是JavaScript Object Notation的首字母缩写。
它是一种经常用于传输数据的格式,但格式良好的JSON是格式良好的JS文字符号。这么多,你只能eval一个JSON字符串,但 无论你做什么,都不要 More details can be found here

尽管如此,你获得的任何解决方案都将是一个JavaScript解决方案,因为jQ是JavaScript ...你在JS中所做的一切都在jQ中运行,每个涉及你编写的jQ的语句都会评估一系列函数调用和构成jQ工具包的其他魔法,无论如何都是用简单的'ol VanillaJS编写的。

然而,回到你的问题。看看你的结构,我认为我说的是每个children属性是一个包含对象的数组,它们可能具有page属性。此属性将分配一个对象。这些都是我的假设,但我得到的印象是这就是这种情况。这意味着,要扩展这个对象,一个简单的map-callback-function就足够了:

yourArray = yourArray.map(function ext(obj)
{//named callback function, does not pollute global scope
   obj.title = "title";
   obj.score = 5.3;
   if (obj.children instanceOf Array)
   {//recursively apply callback
       obj.children = obj.children.map(ext);//reference to current callback function
   }
   return obj;//return altered object
});

这将映射每个数组,为对象分配属性,然后检查是否存在children属性,也是一个数组,并应用相同的回调函数来映射该数组,从而呈现此映射递归的 因为我们在这里处理对象,所以return obj语句实际上是可选的,因为对象是引用:

yourArray.map(function ext(obj)
{//no assignment
   obj.title = "title";
   obj.score = 5.3;
   if (obj.children instanceOf Array)
   {
       obj.children = obj.children.map(ext);
   }
});

同样有效 使用jQuery的extend方法,你可以缩短这个代码,但实际上并不多(实际上是1行):

yourArray = yourArray.map(function ext(obj)
{
   $.extend(obj, {title: 'title',score: 5.3});
   if (obj.children instanceOf Array)
   {
       obj.children = obj.children.map(ext);
   }
   return obj;
});

或者,甚至更多jQ风味:

$.each(yourArray, function ext(i, obj)
{
    $.extend(obj, {title: 'title', score: 5.3});
    if (obj.children instanceof Array)
    {
        $.each(obj.children(ext));
    }
});

但正如您所看到的,在可读性和代码紧凑性方面,差异相当小。所有的jQ都在这里,真的,你慢下来,是残酷的诚实 因为$.extend需要一个对象作为第二个参数,所以我必须在每次调用回调时构造一个对象文字。我不能使用一个对象,它被分配给一个驻留在更高范围内的变量,因为如前所述:永远不会复制对象,只有对它们的引用。使用更高范围的变量会使代码更容易出错:

var extendObj = {title: 'title', score: 4};
yourArray = yourArray.map(function ext(obj)
{
   $.extend(obj, extendObj);
   if (obj.children instanceOf Array)
   {
       obj.children = obj.children.map(ext);
   }
   return obj;
});

这可以完美地运作,但是

var extendObj = {title: 'title', score: 4, deep:{another: 'object'}};

需要深度克隆:

$.extend(true, obj, extendObj);

如果您忘记/忽略这一点,将deep的属性更改为一个实例,则意味着所有其他实例也会反映相同的更改...不理想