javascript - 在嵌套对象中查找对象:超出最大调用堆栈大小
问题描述
我有一个对象数组,我想遍历它并返回文本属性等于给定字符串参数的嵌套对象。例如,文本属性为“预约内部采访”的对象。要查找的对象可以位于层次结构的任何级别。
我正在尝试这样的事情,但它只允许我查看特定级别:
var txt = "Book an Internal Interview";
var obj = items[0].items[0].items.find(o => o.text === txt);
所以我尝试了一个递归解决方案:
var txt = "Book an Internal Interview";
var obj = customFilter(items, txt)
function customFilter(object, text) {
if (object.hasOwnProperty('text') && object["text"] == text)
return object;
for (var i = 0; i < Object.keys(object).length; i++) {
if (typeof object[Object.keys(object)[i]] == "object") {
var o = customFilter(object[Object.keys(object)[i]],text);
if (o != null)
return o;
}
}
return null;
}
但我收到一个错误:
超出最大调用堆栈大小
这是我的对象在控制台中的样子:
0:
action: ""
id: "1"
items: Array(18)
0:
action: "http://localhost:8085/secure/contacts/create.aspx?CandidateID=2256"
id: "20"
label: "Convert to Contact"
leaf: true
level: 1
parent: {id: "1", parentid: "-1", action: "", typeAction: "", text: "Workflow", …}
parentid: "1"
text: "Convert to Contact"
typeAction: "url"
uid: "20"
1:
action: "deleteCandidate(2256);"
id: "2"
label: "Delete"
leaf: true
level: 1
parent: {id: "1", parentid: "-1", action: "", typeAction: "", text: "Workflow", …}
parentid: "1"
text: "Delete"
typeAction: "method"
uid: "2"
2: {id: "21", parentid: "1", action: "ResetModal(); $('#TemplateDialog').dialog('open'); candidateID = 2256", typeAction: "method", text: "Generate Document", …}
3:
action: ""
id: "15"
items: Array(2)
0:
action: "bookClientInterviewSingleCandidate('46','2256')"
id: "16"
label: "Book a Client Interview"
leaf: true
level: 2
parent: {id: "15", parentid: "1", action: "", typeAction: "", text: "Interviews", …}
parentid: "15"
text: "Book a Client Interview"
typeAction: "method"
uid: "16"
1:
action: "bookClientInterviewInternalSingleCandidate('0','2256')"
id: "17"
label: "Book an Internal Interview"
leaf: true
level: 2
parent: {id: "15", parentid: "1", action: "", typeAction: "", text: "Interviews", …}
parentid: "15"
text: "Book an Internal Interview"
typeAction: "method"
uid: "17"
label: "Interviews"
level: 1
parent: {id: "1", parentid: "-1", action: "", typeAction: "", text: "Workflow", …}
parentid: "1"
text: "Interviews"
typeAction: ""
uid: "15"
4:
action: "DisplayLinkToJobForCandidate('modalDisplay', '2256', 'Abigail Hotmail')"
id: "19"
label: "Link To Job"
leaf: true
level: 1
parent: {id: "1", parentid: "-1", action: "", typeAction: "", text: "Workflow", …}
parentid: "1"
text: "Link To Job"
typeAction: "method"
uid: "19"
5: {id: "18", parentid: "1", action: "loadMessageCenterSingleCandidate(2256)", typeAction: "method", text: "Send Email", …}
6: {id: "14", parentid: "1", action: "submitCVSingleCandidate('46','2256')", typeAction: "method", text: "Submit CV", …}
.............
解决方案
如评论中所述,您的输入对象具有循环引用,这意味着嵌套的子对象具有对其祖先之一的引用(可能该parent
属性就是这种情况)。因此,您的代码将无休止地遵循这样的“循环”路径。
Set
您可以通过保留访问对象来保护您的代码免受此影响。
function customFilter(object, text, visited = new Set) {
if (!object || visited.has(object)) return; // Do not go into loops and ignore nulls
visited.add(object);
if (object.hasOwnProperty('text') && object["text"] == text)
return object;
for (var i = 0; i < Object.keys(object).length; i++) {
if (typeof object[Object.keys(object)[i]] == "object") {
var o = customFilter(object[Object.keys(object)[i]], text, visited);
if (o != null)
return o;
}
}
return null;
}
所以:
- 该函数有一个额外的
Set
参数。您不需要在初始调用中指定它,因为默认情况下它将是一个空 Set,但递归调用应该传递第三个参数 - 它检查对象是否已经在集合中。如果是这样,它就会退出。
- 否则它将对象添加到集合中
这Set
将消耗一些内存(与原始输入大小成线性关系)。如果您知道它parent
是负责此类反向引用的属性,那么您也可以通过从循环中排除该属性来解决它。
推荐阅读
- java - 在 Catalina 上全新安装后尝试使用 sbt 运行 Play Scala 应用程序时出错:“加载 JNotify 监视服务时出错:null”
- android - 我的证书更新后我的应用程序停止工作
- python - 无法使用 ChemDataExtractor 在 Windows 10 中执行“cde 数据下载”
- apache-spark - 如何在 PySpark 中读取由多个字符分隔的文本文件?
- wordpress - Wordpress Json 解码
- python - 如何在不让其他值乱序的情况下对堆叠的 numpy 数组进行排序
- javascript - Vue.js this.$nextTick() 似乎没有等待 dom 渲染
- python - 如何在python中创建一个zip文件
- docusignapi - 发送信封时认证失败
- html - 使网格列适应其内容