Есть ли способ обойти потенциально самостоятельный объект в JavaScript?

Я хочу спустить объект в Javascript в поисках определенной строки. К сожалению, этот объект построен таким образом, что было бы невозможно просто использовать источник и Ctrl-F для этой строки, а также он построен таким образом, что рекурсивные функции, пытающиеся спуститься по нему, рискуют застрять внутри него. навсегда.

По сути, этот объект содержит сам себя. Не один раз, а во многих областях. Я не могу просто сказать «исключить эти ключи», так как объект запутан, и поэтому мы будем здесь весь день перечислять ключи, и как только мы закончим, мы не будем смотреть все данные.
Кроме того, мне нужно иметь возможность спускаться по __proto__ и prototype, так как там тоже спрятаны полезные строки. (Но только для функций и объектов.)

Хотя я бы предпочел что-то вроде findStuff(object, /string/ig), это может быть сложно, поэтому любая функция, которая просто имеет четко обозначенные области, на которые падает поток управления, как только она находит определенные объекты (функцию, строку и т.

Спасибо, и извините за такой боль в прикладе вопрос.


Обновлено: если это поможет, я пытаюсь пройти скомпилированный объект времени выполнения Construct2. Я не собираюсь публиковать здесь все целиком, так как оно не поместится ни в какой pastebin, каким бы прощающим оно ни было, а также я не хочу случайно публиковать ресурсы, на предоставление которых у меня нет разрешения. (Не волнуйтесь, я не пытаюсь пиратить его сам, я просто пытаюсь выяснить некоторые функциональные возможности, ориентированные на пользователя)

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
0
115
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вы можете использовать WeakSet для отслеживания уже пройденных объектов:

 function traverseOnce(obj, cb) {
   const visited = new WeakSet();
   (function traverse(obj) {
     for(const [key, value] of Object.entries(obj)) {
       if (typeof value === "object" && value !== null) {
          if (visited.has(value)) continue;
          visited.add(value);
          cb(value);
          traverse(value);
       }
      }
   })(obj);
 }

С помощью WeakSet вы получаете время поиска O(1), а также уверены, что это никогда не утечет.

Используется как:

 const nested = { other: { a: 1 } };
 nested.self = nested;

 traverseOnce(nested, console.info);
 // nested: { other, self }
 // other: { a: 1 }

Вы также можете использовать символ для обозначения пройденных объектов, для этого замените new WeakSet() на Symbol(), visited.has(value) на value[visited] и visuted.add(value) на value[visited] = true;

Использовал WeakSet просто потому, что, хотя идея Symbol чрезвычайно умна, она изменяет состояние каждого пройденного объекта, что не очень хорошо. Спасибо!

Twilight Sparkle 08.04.2019 16:43

«Что «лучше» должно быть определено в вашем сценарии использования». - Я бы сказал, что подход (Weak)Set лучше во всех случаях, потому что вся необходимая вам очистка - это просто выход из функции, без каких-либо недостатков, которые я вижу.

Amadan 08.04.2019 16:43

@amadan Это поддерживает мое мышление. Если функция завершается, WeakSet должен быть проверен, в то время как символ довольно легкий. С другой стороны, я предполагаю, что флаг будет сохранен на объектах, что означает, что их размер немного увеличивается, и скрытый класс должен быть изменен при добавлении флага. Это, вероятно, преждевременная оптимизация, хотя

Jonas Wilms 08.04.2019 16:47

@JonasWilms Разве delete visited; в конце traverseOnce не исправит все это для WeakMap?

Twilight Sparkle 08.04.2019 16:49

@no_boot_device, тем не менее, сборщик мусора срабатывает. Думаю, я слишком много думаю. «он изменяет состояние каждого пройденного объекта»… вы правы. Думаю, я должен перевернуть свой ответ

Jonas Wilms 08.04.2019 17:03

Каждый раз, когда вы проходите потенциально циклический объект, сохранение памятки об уже пройденных объектах и ​​прерывание, если вы видели текущий объект раньше, является стандартной техникой. Для этого вы можете использовать Set.

Сохраните список объектов, к которым вы выполняли рекурсию, а затем проверяйте каждый новый объект по этому списку.

const data = {
  foo: {
    bar: 1
  },
  one: 1,
  jaz: {
    hello: {
      x: 1
    }
  }
};

data.bar = data.foo;
data.foo.foo = data.foo;
data.jaz.hello.foo = data;

function search_for_1() {
  const seen = [];
  search(data);

  function search(object) {
    Object.values(object).forEach(value => {
      if (typeof value === "object") {
        if (seen.includes(value)) {
          console.info("Seen this already");
        } else {
          seen.push(value);
          search(value);
        }
      } else {
        if (value === 1) {
          console.info("Found 1");
        }
      }
    });
  }
}

search_for_1();

Я бы сказал, что поиск WeakSet гораздо более эффективен, чем поиск по массиву, однако, может ли он использоваться, зависит от среды.

Jonas Wilms 08.04.2019 16:36

Не изобретайте велосипед. Для таких вещей существуют библиотеки.

Мы используем объектное сканирование для всей обработки данных. Это очень мощно, как только вы обернете вокруг себя голову. Вот как это будет работать для ваших вопросов

// const objectScan = require('object-scan');

const traverse = (data) => objectScan(['**'], {
  filterFn: ({ key, value, parent }) => {
    // do something here
  },
  breakFn: ({ isCircular }) => isCircular === true
})(data);

const circular = { name: 'Max', age: 5, sex: undefined, details: { color: 'black', breed: undefined } };
circular.sex = circular;
circular.details.breed = circular;

console.info(traverse(circular));
/* =>
 [ [ 'details', 'breed' ],
   [ 'details', 'color' ],
   [ 'details' ],
   [ 'sex' ],
   [ 'age' ],
   [ 'name' ] ]
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src = "https://bundle.run/[email protected]"></script>

Отказ от ответственности: я автор объектное сканирование

Другие вопросы по теме