Поиск объекта во вложенном объекте: превышен максимальный размер стека вызовов - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть массив объектов, который я хочу перебрать и вернуть вложенный объект, где свойство text равно заданному строковому параметру.Например, объект, у которого свойство text - «Записать внутреннее интервью».Объект для поиска может быть на любом уровне иерархии.

Я пытался что-то вроде этого, но это просто позволяет мне смотреть на определенном уровне:

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", …}
            .............

1 Ответ

0 голосов
/ 28 февраля 2019

Как указано в комментариях, ваш входной объект имеет циклические ссылки, что означает, что вложенный дочерний объект имеет ссылку на одного из его предков (вероятно, свойство 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 будет занимать некоторое количество памяти (линейно по отношению к исходному размеру ввода).Если вы знаете, что именно свойство parent отвечает за такие обратные ссылки, вы также можете решить его, исключив это свойство из цикла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...