Я пытаюсь написать функцию, которая будет выводить рекурсивное дерево window
для всех браузеров.Проблема, которую я сразу понял, у меня возникла, была связана с бесконечными объектами (window.window.window.window
).Просто ради смеха, я все равно попробовал, и получил ошибку, как и ожидал.Uncaught RangeError: Maximum call stack size exceeded
(тестирование в Chrome)
Итак, первый подход к проверке объектов, которые должны были вызвать это, был просто:
if (variable != 'window' && variable != 'top' && variable != 'self' && variable != 'frames')
Я думаю, возможно, это сработало бы,и я просто пропустил пару.Это была хорошая теория, но я все равно получаю максимальную ошибку стека.Поэтому я решил набрать window
в консоли Chrome и вручную найти все типы [DOMWindow]
, чтобы добавить в этот список.При этом я заметил значение Infinity: Infinity
, которое привело меня к следующему подходу:
if (typeof namespace[variable]['Infinity'] === 'undefined')
Я все еще получил ошибку максимального стека с этим, поэтому я немного поискал в Google и узнал,о isFinite
, так что теперь у меня есть: (редактировать: на самом деле я только что понял, isFinite
не то, что я думал)
if (isFinite(tree[variable]))
Ошибка, наконец, ушла, но проблема с этим подходомв том, что все объекты в window
возвращают false для этого, поэтому рекурсия не выполняется.Я понимаю, что некоторые из этих подходов, вероятно, не совместимы даже с несколькими браузерами, но было бы неплохо, если бы я смог заставить его хотя бы работать в одном браузере за это время.
Так как я могу проверитьдля объектов, которые будут вызывать бесконечный цикл?
Вот мой код, просто для всех, кого это может заинтересовать:
(function () {
window.onload = function () {
window.onload = ''; // don't want to get our own code
console.log((function (namespace) {
tree = {};
for (var variable in namespace) {
/* gonna need these later
var variable_typeof = typeof namespace[variable],
variable_object_tostring = Object.prototype.toString(namespace[variable]);
*/
//if (variable != 'window' && variable != 'top' && variable != 'self' && variable != 'frames')
//if (typeof namespace[variable]['Infinity'] === 'undefined')
if (isFinite(tree[variable]))
tree[variable] = arguments.callee(namespace[variable]);
else tree[variable] = 'Infinity';
}
return tree;
})(window)); // Start from root
}
})();
Обновление: Вот рабочий продукт того, что я наконец придумала, для всех, кто заинтересован. GGG заслуживает упоминания за его помощь.
function loop (namespace) {
if (namespace['__infinite_test']) return '[[recursion]]'; // It's infinite
namespace['__infinite_test'] = true; // Note that we've been through this object
var tree = {};
for (var variable in namespace) {
try { // For an issue in Chrome throwing an error
namespace[variable]['__tester'] = null;
delete namespace[variable]['__tester'];
}
catch (e) {
tree[variable] = namespace[variable];
continue;
}
if (namespace.propertyIsEnumerable(variable)) tree[variable] = loop(namespace[variable]);
else tree[variable] = namespace[variable];
}
return tree;
}
console.log(loop(window));