Как искать значение во вложенных объектах?

Возьмем такой объект, для примера:

{a: {b: {message: 1, d: {message: 2}}}};

Как найти все message без рекурсии или с ее хвостовой оптимизацией.

Объекты могут быть очень большими, больше, чем в примере, есть риск "словить" переполнение стека. А оптимизацию хвостовой рекурсии корректно имплементировать не смог.

Update 1:

function objectScale() {
    let scaled = {message: 'test'};

    for (let i = 0; i < 1e6; i++) {
        scaled = {scaled, message: '1'};
    }

    return scaled;
}

const object = objectScale();

Как найти все message в object? Скажем, добавить их в массив?

Update 2:

Пример результата:

[1, 1, 1, 1, 1, 1] (получен от array.push(message), где message - 1)

Ответы (1 шт):

Автор решения: Grundy

Объект можно рассматривать в качестве графа: корнем является сам объект, а ветвями - свойства.

Таким образом задача сводится к обходу графа в глубину либо в ширину.

Для этого достаточно хранить все доступные ветки в массиве и в цикле постепенно исключать их, добавляя при этом дочерние ветки.

Для более удобной работы можно воспользоваться методом Object.entries, позволяющий получить список ключей и их значений.

function objectScale() {
  let scaled = {
    message: 'test'
  };

  for (let i = 0; i < 5; i++) {
    scaled = {
      scaled,
      message: 'test' + (i + 1)
    };
  }

  return scaled;
}

const object = objectScale();

function find(o, findkey) {
  var entries = Object.entries(o); // получаем дочерние узлы
  var result = [];
  while (entries.length) { // пока есть непроверенные узлы
    var [key, val] = entries.pop(); // берем один узел
    if (key == findkey) result.push(val); // если ключ соответствует искомому - добавляем результат

    // если значение является объектом
    if (val != null && typeof val == 'object') entries.push(...Object.entries(val)); // добавляем его дочерние узлы в список непроверенных
  }

  return result;
}

console.log(find(object, 'message'))

→ Ссылка