我有一个递归的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中?
答案 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
的属性更改为一个实例,则意味着所有其他实例也会反映相同的更改...不理想