Jak znaleźć funkcję dzwoniącego w JavaScript?


865
function main()
{
   Hello();
}

function Hello()
{
  // How do you find out the caller function is 'main'?
}

Czy istnieje sposób na sprawdzenie stosu wywołań?


63
Mam nadzieję, że pomoże to w debugowaniu. Różne zachowanie w zależności od osoby dzwoniącej to zły pomysł.
Dz.U.

Kiedy byłoby to przydatne do debugowania?
Anderson Green,

33
@AndersonGreen, gdy masz na przykład domyślną metodę renderowania szablonu i widzisz, że jest ona wywoływana dwukrotnie. Zamiast przeczesywać tysiąca LoC lub mozolne przechodzenie przez debugger, możesz po prostu zobaczyć, jaki był wtedy stos.
tkone

28
aby zobaczyć ślad stosu, użyj console.trace () dla chrome. nie wiem jednak o innych
lukas.pukenis 10.10.13

5
Dlaczego to zły pomysł?
Jacob Schneider

Odpowiedzi:


994
function Hello()
{
    alert("caller is " + Hello.caller);
}

Pamiętaj, że ta funkcja jest niestandardowa , ponieważ Function.caller:

Niestandardowy
Ta funkcja jest niestandardowa i nie jest na standardowym torze. Nie używaj go w witrynach produkcyjnych z dostępem do Internetu: nie będzie działać dla każdego użytkownika. Mogą również występować duże niezgodności między implementacjami, a zachowanie może ulec zmianie w przyszłości.


Poniżej znajduje się stara odpowiedź z 2008 roku, która nie jest już obsługiwana w nowoczesnym JavaScript:

function Hello()
{
    alert("caller is " + arguments.callee.caller.toString());
}

254
arguments.callee.caller.nameotrzyma nazwę funkcji.
Rocket Hazmat

137
„Funkcje„ caller ”,„ callee ”i„ arguments ”mogą nie być dostępne dla funkcji trybu ścisłego lub obiektów argumentów dla wywołań do nich” - są przestarzałe w ES5 i usuwane w trybie ścisłym.
ThatGuy,

12
Działa to tylko wtedy, gdy nie używasz trybu ścisłego. Więc usunięcie 'use strict';może pomóc.
pvorb

23
argumentsMożna uzyskać do niego dostęp z funkcji w trybie ścisłym, głupotą byłoby przestać to robić. po prostu nie z function.arguments z zewnątrz. Ponadto, jeśli masz nazwany argument, jego forma argumentów [i] nie będzie śledzić zmian, które wprowadzasz w nazwanej wersji wewnątrz funkcji.
rvr_jon

41
Ta metoda stała się przestarzała, ponieważ ten wpis został wymieniony w 2011 r. Preferowaną metodą jest teraz Function.caller (od 2015 r.).
Greg

152

Ślad stosu

Cały ślad stosu można znaleźć za pomocą kodu specyficznego dla przeglądarki. Dobrą rzeczą jest to, że ktoś już to zrobił ; oto kod projektu na GitHub .

Ale nie wszystkie wiadomości są dobre:

  1. Śledzenie stosu jest bardzo powolne, więc bądź ostrożny (przeczytaj to więcej).

  2. Musisz zdefiniować nazwy funkcji, aby ślad stosu był czytelny. Ponieważ jeśli masz taki kod:

    var Klass = function kls() {
       this.Hello = function() { alert(printStackTrace().join('\n\n')); };
    }
    new Klass().Hello();
    

    Google Chrome ostrzega, ... kls.Hello ( ...ale większość przeglądarek oczekuje nazwy funkcji tuż po słowie kluczowym functioni traktuje ją jako funkcję anonimową. Nawet Chrome nie będzie mógł użyć tej Klassnazwy, jeśli nie podasz klsjej funkcji.

    Nawiasem mówiąc, możesz przejść do funkcji printStackTrace opcję, {guess: true}ale nie znalazłem żadnej prawdziwej poprawy.

  3. Nie wszystkie przeglądarki podają te same informacje. To znaczy parametry, kolumna kodu itp.


Nazwa funkcji dzwoniącego

Nawiasem mówiąc, jeśli chcesz tylko nazwę funkcji wywołującej (w większości przeglądarek, ale nie IE), możesz użyć:

arguments.callee.caller.name

Pamiętaj jednak, że ta nazwa będzie następować po functionsłowie kluczowym. Nie znalazłem sposobu (nawet w Google Chrome), aby uzyskać więcej bez uzyskania kodu całej funkcji.


Kod funkcji dzwoniącego

I podsumowując pozostałe najlepsze odpowiedzi (autor: Pablo Cabrera, Nourdine i Greg Hewgill). Jedyną i naprawdę bezpieczną rzeczą, jakiej można używać w różnych przeglądarkach, jest:

arguments.callee.caller.toString();

Który pokaże kod funkcji dzwoniącego. Niestety, to mi nie wystarcza i dlatego udzielam wskazówek dotyczących StackTrace i nazwy funkcji wywołującej (chociaż nie są one obsługiwane przez różne przeglądarki).


1
być może warto dodać Function.callerza @ odpowiedź Grega
Zach Lysobey

Function.callernie będzie jednak działać w trybie ścisłym.
Rickard Elimää

54

Wiem, że wspomniałeś o „w Javascript”, ale jeśli celem jest debugowanie, myślę, że łatwiej jest po prostu użyć narzędzi programistycznych przeglądarki. Tak to wygląda w Chrome: wprowadź opis zdjęcia tutaj Po prostu upuść debugger w miejscu, w którym chcesz sprawdzić stos.


3
To stare pytanie ... ale jest to zdecydowanie najnowszy i najbardziej aktualny sposób na zrobienie tego dzisiaj.
markstewie

53

Podsumowując (i czyniąc to jaśniejszym) ...

ten kod:

function Hello() {
    alert("caller is " + arguments.callee.caller.toString());
}

jest równoważne z tym:

function Hello() {
    alert("caller is " + Hello.caller.toString());
}

Oczywiście pierwszy bit jest bardziej przenośny, ponieważ możesz zmienić nazwę funkcji, powiedz z „Hello” na „Ciao”, i nadal wszystko działa.

W tym ostatnim przypadku, jeśli zdecydujesz się na refaktoryzację nazwy wywoływanej funkcji (Hello), będziesz musiał zmienić wszystkie jej wystąpienia :(


7
arguments.callee.caller zawsze ma wartość null na Chrome 25.0.1364.5 dev
Kokizzu

53

Możesz uzyskać pełny stacktrace:

arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller

Dopóki dzwoniący nie jest null.

Uwaga: powoduje nieskończoną pętlę funkcji rekurencyjnych.


2
Przepraszam za późną odpowiedź, ale nie widziałem wcześniej twojego komentarza; tylko w przypadku rekurencji nie działa, w innych przypadkach powinno działać.
ale5000

45

Zwykle używam (new Error()).stackw Chrome. Zaletą jest to, że daje to również numery linii, w których dzwoniący wywołał funkcję. Minusem jest to, że ogranicza długość stosu do 10, dlatego przede wszystkim trafiłem na tę stronę.

(Używam tego do zbierania stosów wywołań w konstruktorze niskiego poziomu podczas wykonywania, do przeglądania i debugowania później, więc ustawienie punktu przerwania nie jest przydatne, ponieważ zostanie uderzony tysiące razy)


Czy mógłbyś dodać nieco więcej opisu na temat przedstawionego wyjaśnienia?
abarisone

6
To jedyna rzecz, którą mogę wziąć do pracy, gdy 'use strict';jest na miejscu. Podaj mi informacje, których potrzebowałem - dzięki!
Jeremy Harris

4
Jeśli chodzi o limit długości stosu ... możesz to zmienić za pomocą „Error.stackTraceLimit = Infinity”.
Tom

(nowy błąd („StackLog”)). stack.split („\ n”) ułatwia czytanie.
Teoman shipahi

36

Jeśli nie zamierzasz go uruchamiać w IE <11, to powinna pasować console.trace () .

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

main()
// Hello @ VM261:9
// main @ VM261:4

To działa! Należy dodać więcej głosów
Krunal Panchal

22

Możesz użyć Function.Caller, aby uzyskać funkcję wywoływania. Stara metoda wykorzystująca argument.caller jest uważana za przestarzałą.

Poniższy kod ilustruje jego użycie:

function Hello() { return Hello.caller;}

Hello2 = function NamedFunc() { return NamedFunc.caller; };

function main()
{
   Hello();  //both return main()
   Hello2();
}

Uwagi na temat przestarzałego argumentu. Caller: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

Pamiętaj, Function.caller jest niestandardowy: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller


1
To jest właściwa odpowiedź w tych dniach. Nie możesz już robić rzeczy arguments.caller.callee. Szkoda, że ​​nie możemy przenieść tego na szczyt, ponieważ wszystkie inne rzeczy są już nieaktualne.
coblr

4
Wydaje się, że nie jest to możliwe w trybie ścisłym? Cannot access caller property of a strict mode function
Zach Lysobey,

Funkcja Function.caller również nie działała dla mnie w trybie ścisłym. Ponadto, zgodnie z MDN , call.funkcja jest niestandardowa i nie powinna być używana w produkcji. Może to jednak działać podczas debugowania.
jkdev

Nie miałem problemu z niestandardowym, jeśli działał w węźle, ale po prostu nie jest dozwolony w trybie ścisłym (testowałem na węźle 6.10). To samo dotyczy „argumentów”. Pojawia się komunikat o błędzie: „” obiekt wywołujący ”i„ argumenty ”są ograniczonymi właściwościami funkcji i nie można do nich uzyskać dostępu w tym kontekście.”
Tom

21

Zrobiłbym to:

function Hello() {
  console.trace();
}

To działa świetnie! należy zaakceptować jako prawidłową odpowiedź, ponieważ inne sposoby są już stare \ już nie działają
Yuval Pruss



16

Wygląda na to, że jest to dość rozwiązane pytanie, ale niedawno odkryłem, że callee nie jest dozwolony w „trybie ścisłym”, więc dla własnego użytku napisałem klasę, która dostanie ścieżkę od miejsca, w którym się nazywa. Jest to część małej biblioteki pomocnika i jeśli chcesz użyć samodzielnego kodu, zmień przesunięcie użyte do zwrócenia śladu stosu programu wywołującego (użyj 1 zamiast 2)

function ScriptPath() {
  var scriptPath = '';
  try {
    //Throw an error to generate a stack trace
    throw new Error();
  }
  catch(e) {
    //Split the stack trace into each line
    var stackLines = e.stack.split('\n');
    var callerIndex = 0;
    //Now walk though each line until we find a path reference
    for(var i in stackLines){
      if(!stackLines[i].match(/http[s]?:\/\//)) continue;
      //We skipped all the lines with out an http so we now have a script reference
      //This one is the class constructor, the next is the getScriptPath() call
      //The one after that is the user code requesting the path info (so offset by 2)
      callerIndex = Number(i) + 2;
      break;
    }
    //Now parse the string for each section we want to return
    pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
  }

  this.fullPath = function() {
    return pathParts[1];
  };

  this.path = function() {
    return pathParts[2];
  };

  this.file = function() {
    return pathParts[3];
  };

  this.fileNoExt = function() {
    var parts = this.file().split('.');
    parts.length = parts.length != 1 ? parts.length - 1 : 1;
    return parts.join('.');
  };
}

Nie działa dla mnie function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a()w konsoli (nie próbowałem w pliku), ale wydaje się mieć rozsądny pomysł. Powinien być mimo to oceniany za widoczność.
ninjagecko

Pomysł jest świetny. Analizuję inaczej, ale w aplikacjach nw.js jest to naprawdę jedyny pomysł, który daje to, czego szukam.
Andrew Grothe

Podaj przykład, jak wywołać tę funkcję.
pd_au,


11

Wystarczy, że konsola zarejestruje stos błędów. Możesz wtedy wiedzieć, jak się nazywasz

const hello = () => {
  console.log(new Error('I was called').stack)
}

const sello = () => {
  hello()
}

sello()


10

Aktualizacja 2018

callerjest zabronione w trybie ścisłym . Oto alternatywa przy użyciu (niestandardowego) Errorstosu .

Poniższa funkcja wydaje się wykonywać tę pracę w Firefoksie 52 i Chrome 61-71, chociaż jej implementacja zawiera wiele założeń dotyczących formatu rejestrowania dwóch przeglądarek i powinna być używana ostrożnie, biorąc pod uwagę, że zgłasza wyjątek i prawdopodobnie wykonuje dwa wyrażenia regularne dopasowania przed zakończeniem.

'use strict';
const fnNameMatcher = /([^(]+)@|at ([^(]+) \(/;

function fnName(str) {
  const regexResult = fnNameMatcher.exec(str);
  return regexResult[1] || regexResult[2];
}

function log(...messages) {
  const logLines = (new Error().stack).split('\n');
  const callerName = fnName(logLines[1]);

  if (callerName !== null) {
    if (callerName !== 'log') {
      console.log(callerName, 'called log with:', ...messages);
    } else {
      console.log(fnName(logLines[2]), 'called log with:', ...messages);
    }
  } else {
    console.log(...messages);
  }
}

function foo() {
  log('hi', 'there');
}

(function main() {
  foo();
}());


4
To niesamowite, a także przerażające.
Ian

Dostałem „foo wezwany przez: cześć tam”, ale foo nie został wywołany przez „cześć tam”, log został wywołany przez „cześć tam”
AndrewR

Tak, w gramatyce komunikatu o błędzie był „źle umieszczony modyfikator”. Oznaczało to, że „log został wywołany z funkcji f, chciał wydrukować komunikat X”, ale w możliwie zwięzły sposób.
Rovanion

9

Zarówno w trybie ES6, jak i ścisłym, skorzystaj z poniższych poleceń, aby uzyskać funkcję dzwoniącego

console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])

Należy pamiętać, że powyższa linia wyrzuci wyjątek, jeśli nie ma dzwoniącego lub poprzedni stos. Użyj odpowiednio.


Aby uzyskać callee (obecna nazwa funkcji), użyj: console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
VanagaS

7

Chciałem dodać tutaj moje skrzypce:

http://jsfiddle.net/bladnman/EhUm3/

Testowałem to Chrome, Safari i IE (10 i 8). Działa w porządku. Liczy się tylko jedna funkcja, więc jeśli przestraszy Cię wielkie skrzypce, przeczytaj poniżej.

Uwaga: W tym skrzypce jest sporo mojej własnej „płyty kotłowej”. Możesz to wszystko usunąć i użyć splitów, jeśli chcesz. To po prostu bardzo bezpieczny „zestaw funkcji, na których polegam.

Jest tam również szablon „JSFiddle”, którego używam do wielu skrzypiec, aby po prostu szybko skrzypać.


Zastanawiam się, czy mógłbyś dodać „pomocników” jako rozszerzenia prototypu w niektórych przypadkach, na przykład:String.prototype.trim = trim;
autystyczny

6

Jeśli potrzebujesz tylko nazwy funkcji, a nie kodu i chcesz rozwiązania niezależnego od przeglądarki, skorzystaj z następujących opcji:

var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];

Zauważ, że powyższe zwróci błąd, jeśli nie ma funkcji wywołującej, ponieważ w tablicy nie ma elementu [1]. Aby obejść ten problem, skorzystaj z poniższych:

var callerFunction = (arguments.callee.caller.toString().match(/function ([^\(]+)/) === null) ? 'Document Object Model': arguments.callee.caller.toString().match(/function ([^\(]+)/)[1], arguments.callee.toString().match(/function ([^\(]+)/)[1]);


5

Po prostu chcę poinformować, że w dniu PhoneGap / Androidname robi wydaje się działać. Ale arguments.callee.caller.toString()załatwi sprawę.


4

Tutaj wszystko z wyjątkiem functionnamejest usuwane caller.toString()z RegExp.

<!DOCTYPE html>
<meta charset="UTF-8">
<title>Show the callers name</title><!-- This validates as html5! -->
<script>
main();
function main() { Hello(); }
function Hello(){
  var name = Hello.caller.toString().replace(/\s\([^#]+$|^[^\s]+\s/g,'');
  name = name.replace(/\s/g,'');
  if ( typeof window[name] !== 'function' )
    alert ("sorry, the type of "+name+" is "+ typeof window[name]);
  else
    alert ("The name of the "+typeof window[name]+" that called is "+name);
}
</script>

wciąż zwraca całą deklarację metody
Maslow

4

oto funkcja pozwalająca uzyskać pełny stacktrace :

function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
  stack += '\n' + f.name;
  f = f.caller;
}
return stack;
}

3

W odpowiedziach heystewart i JiarongWu wspomniano, że Errorobiekt ma dostęp do stack.

Oto przykład:

function main() {
  Hello();
}

function Hello() {
  var stack;
  try {
    throw new Error();
  } catch (e) {
    stack = e.stack;
  }
  // N.B. stack === "Error\n  at Hello ...\n  at main ... \n...."
  var m = stack.match(/.*?Hello.*?\n(.*?)\n/);
  if (m) {
    var caller_name = m[1];
    console.log("Caller is:", caller_name)
  }
}

main();

Różne przeglądarki pokazują stos w różnych formatach łańcuchów:

Safari : Caller is: main@https://stacksnippets.net/js:14:8 Firefox : Caller is: main@https://stacksnippets.net/js:14:3 Chrome : Caller is: at main (https://stacksnippets.net/js:14:3) IE Edge : Caller is: at main (https://stacksnippets.net/js:14:3) IE : Caller is: at main (https://stacksnippets.net/js:14:3)

Większość przeglądarek ustawi stos var stack = (new Error()).stack. W Internet Explorerze stos będzie niezdefiniowany - musisz pobrać prawdziwy wyjątek, aby odzyskać stos.

Wnioski: Jest możliwe określenie „główny” to dzwoniący do „Hello” używając stackw Errorobiekcie. W rzeczywistości zadziała w przypadkach, w których podejście callee/ callernie działa. Pokaże także kontekst, tzn. Plik źródłowy i numer linii. Konieczne są jednak starania, aby rozwiązanie było wieloplatformowe.


2

Zauważ, że nie możesz używać Function.caller w Node.js, zamiast tego użyj pakietu identyfikatora rozmówcy . Na przykład:

var callerId = require('caller-id');

function foo() {
    bar();
}
function bar() {
    var caller = callerId.getData();
    /*
    caller = {
        typeName: 'Object',
        functionName: 'foo',
        filePath: '/path/of/this/file.js',
        lineNumber: 5,
        topLevelFlag: true,
        nativeFlag: false,
        evalFlag: false
    }
    */
}

1

Wypróbuj następujący kod:

function getStackTrace(){
  var f = arguments.callee;
  var ret = [];
  var item = {};
  var iter = 0;

  while ( f = f.caller ){
      // Initialize
    item = {
      name: f.name || null,
      args: [], // Empty array = no arguments passed
      callback: f
    };

      // Function arguments
    if ( f.arguments ){
      for ( iter = 0; iter<f.arguments.length; iter++ ){
        item.args[iter] = f.arguments[iter];
      }
    } else {
      item.args = null; // null = argument listing not supported
    }

    ret.push( item );
  }
  return ret;
}

Pracował dla mnie w Firefox-21 i Chromium-25.


Wypróbuj to dla funkcji rekurencyjnych.
daniel1426

arguments.calleejest przestarzałe od wielu lat .
Dan Dascalescu

1

Innym sposobem obejścia tego problemu jest po prostu przekazanie nazwy funkcji wywołującej jako parametru.

Na przykład:

function reformatString(string, callerName) {

    if (callerName === "uid") {
        string = string.toUpperCase();
    }

    return string;
}

Teraz możesz wywołać funkcję w ten sposób:

function uid(){
    var myString = "apples";

    reformatString(myString, function.name);
}

Mój przykład wykorzystuje zakodowane sprawdzenie nazwy funkcji, ale możesz łatwo użyć instrukcji switch lub innej logiki, aby zrobić to, co chcesz.


Wierzę, że to w większości rozwiązuje również problemy ze zgodnością różnych przeglądarek. Ale proszę przetestuj to przed założeniem, że to prawda! ( zaczyna się pocić )
GrayedFox

1

O ile mi wiadomo, mamy na to dwa sposoby z danych źródeł takich jak ten-

  1. arguments.caller

    function whoCalled()
    {
        if (arguments.caller == null)
           console.log('I was called from the global scope.');
        else
           console.log(arguments.caller + ' called me!');
    }
  2. Function.caller

    function myFunc()
    {
       if (myFunc.caller == null) {
          return 'The function was called from the top!';
       }
       else
       {
          return 'This function\'s caller was ' + myFunc.caller;
        }
    }

Myślę, że masz odpowiedź :).


Jest to przestarzałe od wielu lat , a Function.caller nie działa w trybie ścisłym.
Dan Dascalescu

1

Dlaczego wszystkie powyższe rozwiązania wyglądają jak rakieta. Tymczasem nie powinien być bardziej skomplikowany niż ten fragment. Wszystkie kredyty dla tego faceta

Jak znaleźć funkcję dzwoniącego w JavaScript?

var stackTrace = function() {

    var calls = [];
    var caller = arguments.callee.caller;

    for (var k = 0; k < 10; k++) {
        if (caller) {
            calls.push(caller);
            caller = caller.caller;
        }
    }

    return calls;
};

// when I call this inside specific method I see list of references to source method, obviously, I can add toString() to each call to see only function's content
// [function(), function(data), function(res), function(l), function(a, c), x(a, b, c, d), function(c, e)]

3
Oto, co otrzymuję przy użyciu tego: TypeError: właściwości „caller”, „callee” i „arguments” mogą nie być dostępne dla funkcji trybu ścisłego lub obiektów argumentów dla wywołań do nich. Jakieś pomysły, jak pracować w trybie ścisłym?
hard_working_ant

1

Próbuję odpowiedzieć zarówno na pytanie, jak i na obecną nagrodę za pomocą tego pytania.

Nagroda wymaga, aby osoba dzwoniąca została uzyskana w trybie ścisłym , a jedynym sposobem, w jaki mogę to zrobić, jest odwołanie się do funkcji zadeklarowanej poza trybem ścisłym.

Na przykład poniższe elementy są niestandardowe, ale zostały przetestowane z wcześniejszymi (29.03.2016) i aktualnymi (1 sierpnia 2018) wersjami Chrome, Edge i Firefox.

function caller()
{
   return caller.caller.caller;
}

'use strict';
function main()
{
   // Original question:
   Hello();
   // Bounty question:
   (function() { console.log('Anonymous function called by ' + caller().name); })();
}

function Hello()
{
   // How do you find out the caller function is 'main'?
   console.log('Hello called by ' + caller().name);
}

main();



0

Jeśli naprawdę potrzebujesz tej funkcji z jakiegoś powodu i chcesz, aby była kompatybilna z różnymi przeglądarkami i nie martwiła się o surowe rzeczy i była kompatybilna z przekazywaniem, to przekaż następujące odniesienie:

function main()
{
   Hello(this);
}

function Hello(caller)
{
    // caller will be the object that called Hello. boom like that... 
    // you can add an undefined check code if the function Hello 
    // will be called without parameters from somewhere else
}

0

Myślę, że następujący fragment kodu może być pomocny:

window.fnPureLog = function(sStatement, anyVariable) {
    if (arguments.length < 1) { 
        throw new Error('Arguments sStatement and anyVariable are expected'); 
    }
    if (typeof sStatement !== 'string') { 
        throw new Error('The type of sStatement is not match, please use string');
    }
    var oCallStackTrack = new Error();
    console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}

Wykonaj kod:

window.fnPureLog = function(sStatement, anyVariable) {
    if (arguments.length < 1) { 
        throw new Error('Arguments sStatement and anyVariable are expected'); 
    }
    if (typeof sStatement !== 'string') { 
        throw new Error('The type of sStatement is not match, please use string');
    }
    var oCallStackTrack = new Error();
    console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}

function fnBsnCallStack1() {
    fnPureLog('Stock Count', 100)
}

function fnBsnCallStack2() {
    fnBsnCallStack1()
}

fnBsnCallStack2();

Dziennik wygląda następująco:

Call Stack:
    at window.fnPureLog (<anonymous>:8:27)
    at fnBsnCallStack1 (<anonymous>:13:5)
    at fnBsnCallStack2 (<anonymous>:17:5)
    at <anonymous>:20:1 
Stock Count: 100
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.