Javascript 递归扩展json对象

Javascript 递归扩展json对象,javascript,jquery,json,recursion,Javascript,Jquery,Json,Recursion,我有一个递归json结构,其中包含一些属性和一个包含子节点的节点,其格式与需要的深度相同。下面的示例并不完整,也与我的数据不同,但它显示了大致的结构 [{"page":{ title: "my title 1", children: [ {"page":{ title: "my title 2", children: [ ... ] },{"page":{ title: "my

我有一个递归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/对象结构,最好是在jQuery中?

首先,您拥有的是一个对象数组。数组是一个原生JS对象(实际上是
对象
的一个扩展实例)。JS中没有JSON对象,因为JSON是JavaScript对象表示法的首字母缩写。
这是一种通常用于传输数据的格式,但格式良好的JSON是格式良好的JS文字符号。如此之多以至于您可以
eval
一个JSON字符串,但是无论您做什么,都不要

尽管如此,您得到的任何解决方案都将是JavaScript解决方案,因为jQ就是JavaScript。。。您在JS中所做的一切都在jQ中工作,您编写的每一条涉及jQ的语句都会计算为一系列函数调用和构成jQ工具包的其他魔法,所有这些都是用普通的“ol VanillaJS”编写的

然而,回到你的问题上来。看看你的结构,我想我说得对,每个
子属性
都是一个数组,包含对象,可能有一个
页面
属性。此属性将指定一个对象。这些都是我的假设,但我的印象是,这里就是这样。这意味着,要扩展此对象,一个简单的映射回调函数就足够了:

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
});
这将映射每个数组,将属性分配给对象,然后检查是否有
子属性,这也是一个数组,并应用相同的回调函数映射该数组,从而使此映射成为递归映射。
因为我们在这里处理对象,
returnobj
语句实际上是可选的,因为对象是引用:

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
方法,您可以稍微缩短这段代码,但不会缩短太多(实际上是一行),当然:

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;
});
这将非常有效,但是:

需要深度克隆:

$.extend(true, obj, extendObj);

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

首先,您拥有的是一个对象数组。数组是一个原生JS对象(实际上是
对象
的一个扩展实例)。JS中没有JSON对象,因为JSON是JavaScript对象表示法的首字母缩写。
这是一种通常用于传输数据的格式,但格式良好的JSON是格式良好的JS文字符号。如此之多以至于您可以
eval
一个JSON字符串,但是无论您做什么,都不要

尽管如此,您得到的任何解决方案都将是JavaScript解决方案,因为jQ就是JavaScript。。。您在JS中所做的一切都在jQ中工作,您编写的每一条涉及jQ的语句都会计算为一系列函数调用和构成jQ工具包的其他魔法,所有这些都是用普通的“ol VanillaJS”编写的

然而,回到你的问题上来。看看你的结构,我想我说得对,每个
子属性
都是一个数组,包含对象,可能有一个
页面
属性。此属性将指定一个对象。这些都是我的假设,但我的印象是,这里就是这样。这意味着,要扩展此对象,一个简单的映射回调函数就足够了:

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
});
这将映射每个数组,将属性分配给对象,然后检查是否有
子属性,这也是一个数组,并应用相同的回调函数映射该数组,从而使此映射成为递归映射。
因为我们在这里处理对象,
returnobj
语句实际上是可选的,因为对象是引用:

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
方法,您可以稍微缩短这段代码,但不会缩短太多(实际上是一行),当然:

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;
});
这将非常有效,但是:

需要深度克隆:

$.extend(true, obj, extendObj);
如果您忘记/忽略这一点,通过一个实例更改
deep
的属性,则意味着所有其他实例也反映了相同的更改。。。不理想

创建一个fiddl