2013-03-16 12 views
6

W JavaScript, czy jest możliwe uzyskanie listy wszystkich funkcji, które są wywoływane przez inną funkcję? Chcę utworzyć drzewo zależności funkcji, aby przeanalizować, w jaki sposób funkcje w skrypcie są ze sobą powiązane (i które funkcje są wymagane przez inne funkcje).Uzyskaj listę wszystkich funkcji, które są wywoływane przez inną funkcję

Na przykład:

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"); 
} 
+0

Zastanawiam się, czy byłoby to możliwe, aby zrobić coś takiego za pomocą narzędzia do usuwania kodu. Mógłbym po prostu zdefiniować wszystkie funkcje, których potrzebowałam i wywołać tylko funkcję, której wymagane funkcje były mi potrzebne. Następnie użyłbym narzędzia do usuwania kodów wynikowych, aby usunąć wszystkie funkcje, które nie były używane w skrypcie. –

+1

co próbujesz osiągnąć tutaj? – smk

+0

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments/callee –

Odpowiedz

13

Esprima może Ci pomóc. Jest to analizator składni Javascript, który może pomóc Ci w statycznej analizie kodu.

Oto krótki przykład (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); 

Oczywiście to wymaga dużo pomocy do zaoferowania wiele wartości, ale może dać pewne wyobrażenie o tym, co jest możliwe i gdzie zacząć.

+0

W Google Chrome: 'konsola.log (funcs) 'wypisuje' Array [4] 'na konsolę, zamiast drukować zawartość tablicy. Jeśli zamiast tego chcesz wydrukować zawartość 'funcs' na konsoli, możesz użyć' console.log (JSON.stringify (funcs)); '. –

+0

Zrobiłem podobne rozwiązanie, teraz analizuje tylko funkcję deklaracji funkcji i wywołania funkcji https://github.com/sanex3339/javascript-obfuscator/blob/dev/src/StackTraceAnalyzer.ts –

-3

Oczywistą odpowiedzią jest coś jak następuje:

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); 
}; 

ale to faktycznie natychmiast wchodzi w nieskończoną pętlę, bo sam akt nazywając console.log wykonuje wywołanie funkcji , która wywołuje console.log, która wykonuje wywołanie funkcji, które wywołuje console.log, które ...

OR

Zakładam, że chcesz odfiltrować natywne funkcje. Firefox, Function.toString() zwraca ciało funkcji, które dla funkcji natywnych, będzie w formie:

function addEventListener() { 
    [native code] 
} 

Można dopasować wzór /\[native code\]/ w swojej pętli i pominięcie funkcji, które pasują.

+0

Twój kod zakłada, że ​​'.call()' jest wywoływana, gdy funkcje są wywoływane, co nie ma miejsca. – Pointy

+0

Czy istnieje sposób, aby utworzyć demonstrację tego (tak, że mogę zrozumieć, w jaki sposób te funkcje mają być używane)? Poza tym, do której pętli się odwołujesz? Nie widzę pętli for lub loop w dowolnym miejscu w tym przykładzie kodu. –

1

Zasadniczo nie można.

Obiekty/funkcje nie będą wiedzieć, co będą wykonywać, dopóki ich nie wykonasz, O ile nie wykonasz wyrażeń regularnych w samym kodzie skryptu java funkcji .. w najlepszym razie niewiarygodne.

Jeśli chcesz to zrobić w tył, śledzenie stosu z powrotem, pytania, jak to ma rozwiązania: How can I get a Javascript stack trace when I throw an exception?

Aby osiągnąć to, czego prawdopodobnie szuka, można stworzyć ogólną klasę, z której twoje funkcje dziedziczenia, za pomocą własnej zaimplementowanej metody przypisywania im wywołań funkcji.

+0

JavaScript nie może być opisany w zwykłych językach. Będziesz potrzebował pełnego parsera do skasowania kodu treści funkcji: http://www.codinghorror.com/blog/2008/06/regular-expressions-now-you-have-two-problems.html –

+0

To dlaczego nazywam to w najlepszym razie niewiarygodne;). W każdym razie, jeśli celem pytania jest analiza kodu, śledzenie stosu ma na nim narzędzie. – Jaibuu

2

Interesujące pytanie. Ja też zastanawiam się nad motywem, który kryje się za tym ... Mam nadzieję, że wystarczy go po prostu lepiej debugować lub lepiej zrozumieć strukturę aplikacji.

Oto WILD pomysł: tylko rzucanie go tam ...

Jeśli mógłbyś związać do każdej funkcji można uzyskać wywoływany przez:

arguments.callee.name 

I napisać, że do zmienną globalną (być może obiekt, w którym każdy klucz jest nazwą funkcji, a wartość jest tablicą nazw funkcji).

+0

To jest dokładnie to, co pierwotnie myślałem, ale jest kilka problemów. Po pierwsze, nie chcesz zmieniać każdej pojedynczej funkcji. Równie dobrze możesz narysować wykres zależności ręcznie. Po drugie, myślę, że OP chce statycznie określić wykres zależności. To rozwiązanie działa tylko wtedy, gdy program jest wykonywany, a następnie ponownie tylko wtedy, gdy wszystkie funkcje są wywoływane przez wszystkie możliwe funkcje, które mogą wywoływać je w celu utworzenia pełnego wykresu. To tak, jakby równolegle przetwarzać wszystkie możliwe ścieżki kodu w programie. JavaScript nie jest niedeterministycznym językiem programowania. –

+0

@AaditMShah Masz rację, też o tym myślałem. Interesująca informacja jednak, jeśli dodasz 'console.dir (argumenty)' do funkcji i wyświetlisz Konsole w Chrome, możesz przejść do 'arguments.callee. .Closure', i daje oczekiwane funkcje (funcB , funcC i funcD). Nie wiem jednak jak programowo uzyskać '' zakres funkcji> '. Musi być wbudowaną funkcją do devtools? –

Powiązane problemy