7

在 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

4 回答 4

15

Esprima可以帮助您。它是一个 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);

显然,这需要很多帮助才能提供更多价值,但它可能会让您对什么是可能的以及从哪里开始有所了解。

于 2013-03-16T05:28:12.857 回答
2

有趣的问题。我也质疑它背后的动机......希望它只是为了更好地调试或理解应用程序的结构。

这是一个疯狂的想法:只是把它扔在那里......

如果您可以绑定到每个函数,您可以通过以下方式获取被调用者:

arguments.callee.name

并将其写入全局变量(可能是一个对象,每个键是函数的名称,值是函数名称的数组)。

于 2013-03-16T05:21:37.177 回答
1

基本上,你不能。

除非您执行它们,否则对象/函数将不知道它们将执行什么,除非您对函数的 java 脚本代码本身执行正则表达式.. 充其量是不可靠的。

如果你想向后做,追溯堆栈,这样的问题有解决方案:当我抛出异常时,如何获得 Javascript 堆栈跟踪?

为了实现您可能正在寻找的东西,您可以创建一个泛型类,您的函数从该类继承,并使用您自己实现的方法为它们分配函数调用。

于 2013-03-16T05:12:44.467 回答
-3

显而易见的答案如下所示:

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\]/循环中的模式并省略匹配的函数。

于 2013-03-16T05:01:05.047 回答