Получить список всех функций, которые вызываются другой функцией

В JavaScript возможно ли получить список всех функций, которые вызываются другой функцией? Я хочу создать дерево зависимостей функций, чтобы проанализировать, как функции в скрипте связаны друг с другом (и какие функции требуются для каких других функций).

Например:

getAllCalledFunctions(funcA); //this should return [funcB, funcC, funcD], since these are the functions that are required by funcA.

function getAllCalledFunctions(functionName){
    //how should I implement this?
}

function funcA(){
    funcB();
    funcC();
}

function funcB(){
    funcD();
}

function funcC(){
    funcD();
}

function funcD(){
    console.log("This function is called by funcC and funcD");
}

4 ответа

Решение

Эсприма может вам помочь. Это анализатор Javascript, который может помочь вам выполнить статический анализ кода.

Вот быстрый пример ( http://jsfiddle.net/fyBvT/):

var code = 'function funcA() { funcB(); funcC(); } function funcB(){ funcD(); } function funcC() { funcD(); } function funcD(){ console.log("This function is called by funcC and funcD"); }';
var syntax = esprima.parse(code);

var funcs = [];
_.each(syntax.body, function(i) {
    if (i.type == 'FunctionDeclaration') {
        var func = {name: i.id.name};

        _.each(i.body.body, function(j) {
            if (j.type == 'ExpressionStatement' && j.expression.type == 'CallExpression') {
                func.calls = func.calls || [];
                func.calls.push(j.expression.callee.name);
            }
        });

        funcs.push(func);
    }
});

console.log(funcs);

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

Интересный вопрос. Я тоже сомневаюсь в мотиве этого... Надеюсь, это просто для отладки или лучшего понимания структуры приложения.

Вот дикая идея: просто бросить это там...

Если бы вы могли связать каждую функцию, вы можете получить вызываемого абонента:

arguments.callee.name

И запишите это в глобальную переменную (возможно, объект, где каждый ключ является именем функции, а значение - массивом имен функций).

По сути, вы не можете.

Объекты / функции не будут знать, что они будут выполнять, пока вы их не выполните, если вы не выполняете регулярные выражения для самого кода функции java-скрипта функции... в лучшем случае ненадежного.

Если вы хотите сделать это задом наперед, отслеживая стек назад, у вопросов, подобных этому, есть решения: как я могу получить трассировку стека Javascript при выдаче исключения?

Чтобы достичь того, что вы, вероятно, ищете, вы можете создать универсальный класс, от которого наследуются ваши функции, с вашим собственным реализованным методом для назначения им вызовов функций.

Очевидный ответ - что-то вроде следующего:

var origCall = Function.prototype.call;
Function.prototype.call = function (thisArg) {
    console.log("calling a function");

    var args = Array.prototype.slice.call(arguments, 1);
    origCall.apply(thisArg, args);
};

Но это на самом деле сразу же входит в бесконечный цикл, потому что сам акт вызова console.log выполняет вызов функции, которая вызывает console.log, которая выполняет вызов функции, которая вызывает console.log, который...

ИЛИ ЖЕ

Я предполагаю, что вы хотите отфильтровать нативные функции. В Firefox Function.toString() возвращает тело функции, которое для нативных функций будет иметь вид:

function addEventListener() { 
    [native code] 
}

Вы могли бы соответствовать шаблону /\[native code\]/ в вашем цикле и опустите соответствующие функции.

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