Окно дерева рекурсии Javascript и бесконечные объекты - PullRequest
2 голосов
/ 24 февраля 2012

Я пытаюсь написать функцию, которая будет выводить рекурсивное дерево 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));

1 Ответ

2 голосов
/ 24 февраля 2012

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

Когда вы встречаете объект, которого нет в вашем списке, вы добавляете его в свой список, а затем возвращаетесь в него.

...