Pergunta

function main()
{
   Hello();
}

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

Existe uma maneira de descobrir a pilha de chamadas?

Foi útil?

Solução

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

Note que esta característica é não-padrão , de Function.caller :

Não-padrão
Este recurso não é padrão e não é em uma pista de padrões. Não usá-lo nos locais de produção de frente para a Web: ele não vai funcionar para todos os usuários. Também pode haver grandes incompatibilidades entre implementações e o comportamento pode mudar no futuro.


A seguir é a velha resposta a partir de 2008, o que já não é suportada em Javascript moderna:

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

Outras dicas

StackTrace

Você pode encontrar todo o rastreamento de pilha usando código específico browser. A coisa boa é alguém já fez isso ; aqui é o código do projeto no GitHub .

Mas nem todas as notícias são boas:

  1. É muito lento para obter o rastreamento de pilha que deve ter cuidado (leia este para mais).

  2. Você vai precisar para definir nomes de função para o rastreamento de pilha para ser legível. Porque se você tem um código como este:

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

    O Google Chrome irá alertar ... kls.Hello ( ... mas a maioria dos navegadores irá esperar um nome de função logo após a palavra-chave function e vai tratá-lo como uma função anônima. Uma nem mesmo Chrome será capaz de usar o nome Klass se você não dar o nome kls para a função.

    E pelo jeito, você pode passar para o printStackTrace função {guess: true} opção, mas eu não encontrou qualquer melhoria real ao fazer isso.

  3. Nem todos os navegadores dar-lhe a mesma informação. Ou seja, parâmetros, coluna de código, etc.


Caller Nome Função

A propósito, se você quer apenas o nome da função de chamada (na maioria dos navegadores, mas não IE), você pode usar:

arguments.callee.caller.name

Mas note que este nome será o único após a palavra-chave function. Eu não encontrei nenhuma maneira (mesmo no Google Chrome) para obter mais do que isso sem obter o código de toda a função.


Caller Código de Função

E resumindo o resto das melhores respostas (por Pablo Cabrera, Nourdine, e Greg Hewgill). A única cross-browser e coisa realmente seguro você pode usar é:

arguments.callee.caller.toString();

que irá mostrar o Código da função chamador. Infelizmente, isso não é suficiente para mim, e é por isso que eu dar-lhe dicas para o StackTrace ea função de interlocutor Nome (embora eles não são cross-browser).

Para recapitular (e torná-lo mais claro) ...

este código:

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

é equivalente a esta:

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

É evidente que o primeiro bit é mais portátil, desde que você pode alterar o nome da função, digamos, de "Olá" para "Ciao", e ainda obter a coisa toda para o trabalho.

Neste último, no caso de você decidir refatorar o nome da função de chamada (Olá), você teria que mudar todas as suas ocorrências :(

Você pode obter o stacktrace completo:

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

Até chamador é null.

Nota: é causar um loop infinito em funções recursivas

.

Eu sei que você mencionou "em Javascript", mas se o objetivo é depuração, eu acho que é mais fácil simplesmente usar ferramentas de desenvolvimento do seu navegador. Isso é o que parece no Chrome: enter descrição da imagem aqui Basta soltar o depurador onde pretende investigar a pilha.

Eu costumo usar (new Error()).stack no Chrome. O bom é que isso também lhe dá os números de linha onde o chamador chamou a função. A desvantagem é que limita a duração da pilha para 10, que é por isso que vim a esta página em primeiro lugar.

(estou usando isso para callstacks Recolher em um construtor de baixo nível durante a execução, para visualizar e depuração mais tarde, assim, definir um ponto de interrupção não é de uso, uma vez que vai ser atingido milhares de vezes)

Se você não está indo para executá-lo no IE <11, em seguida, console.trace () serviria.

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

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

Você pode usar Function.Caller para obter a função de chamada. O método antigo usando argument.caller é considerado obsoleto.

O código a seguir ilustra o seu uso:

function Hello() { return Hello.caller;}

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

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

Notas sobre argument.caller obsoleto: https: // developer. mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

Esteja ciente Function.caller é não-padrão: https: / /developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller

function Hello() {
    alert(Hello.caller);
}

É mais seguro usar *arguments.callee.caller desde arguments.caller é deprecated ...

Parece que este é uma pergunta muito resolvido, mas eu recentemente descobri que receptor não é permitido em 'modo estrito' assim para meu uso eu escrevi uma classe que irá obter o caminho de onde ele é chamado. É parte de um pequeno ajudante lib e se você quiser usar a mudança autônomo código deslocamento utilizado para devolver o rastreio da pilha do chamador (uso de um em vez de dois)

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('.');
  };
}

Eu faria isso:

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

Tente acessar o seguinte:

arguments.callee.caller.name

log Apenas consola sua pilha de erro. Você pode, então, saber como você está sendo chamado

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

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

sello()

Eu queria acrescentar o meu violino aqui para isso:

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

I testado este é cromo, safari e IE (10 e 8). Funciona bem. Há apenas 1 função que importa, por isso, se você ficar com medo pela grande violino, leia abaixo.

Nota: Há uma quantidade justa de minha própria "clichê" neste violino. Você pode remover tudo isso e utilização fraccionada é, se você gosta. É apenas um conjunto ultra-seguro" de funções que eu vim para confiar.

Há também um "jsFiddle" template lá que eu uso para muitos violinos para mexer simplesmente rápida.

2018 Atualização

caller é proibido no modo estrito . Aqui é uma alternativa utilizando o (não normalizado) Error pilha .

A função a seguir parece estar a fazer o trabalho no Firefox 52 e Chrome 61-71 embora a sua implementação faz um monte de suposições sobre o formato de log dos dois navegadores e deve ser usado com cautela, uma vez que ele lança uma exceção e possivelmente executa dois emparelhamentos regex antes de ser feito.

'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 with:', ...messages);
    } else {
      console.log(fnName(logLines[2]), 'called with:', ...messages);
    }
  } else {
    console.log(...messages);
  }
}

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

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

Se você quiser apenas o nome da função e não o código, e quer uma solução independente de navegador, use o seguinte:

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

Note-se que o acima irá devolver um erro se não há nenhuma função chamador como não há [1] elemento na matriz. Para contornar, use o seguinte:

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

Só quero que você saiba que em PhoneGap / Android o doesnt name parece estar funcionando. Mas arguments.callee.caller.toString() irá fazer o truque.

Aqui, tudo, mas o functionname é despojado de caller.toString(), com 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>

aqui é uma função para get stacktrace completo :

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

de heystewart resposta e a resposta de JiarongWu ambos mencionados que o objeto Error tem acesso ao stack.

Aqui está um exemplo:

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

diferentes navegadores mostra a pilha em diferentes formatos de cadeia:

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)

A maioria dos navegadores irá definir a pilha com var stack = (new Error()).stack. No Internet Explorer a pilha será indefinido - você tem que lançar uma exceção real para recuperar a pilha

.

Conclusão: É possível determinar "principal" é a chamada para "Olá" usando o stack no objeto Error. Na verdade ele vai trabalhar nos casos em que a abordagem callee / caller não funciona. Ele também irá mostrar-lhe contexto, arquivo de origem ou seja, eo número da linha. No entanto esforço é necessário para tornar a plataforma cruzada solução.

Tente o seguinte código:

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

funcionou para mim no Firefox-21 e cromo-25.

Outra maneira de contornar este problema é simplesmente passar o nome da função de chamada como um parâmetro.

Por exemplo:

function reformatString(string, callerName) {

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

    return string;
}

Agora, você poderia chamar a função como esta:

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

    reformatString(myString, function.name);
}

O meu exemplo usa um cheque codificado duro do nome da função, mas você pode facilmente usar um switch ou alguma outra lógica para fazer o que quiser lá.

Tanto quanto eu sei, nós temos 2 vias para este a partir de fontes dadas como este -

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

Pense u tem sua resposta:).

Por que todas as soluções acima olhar como uma ciência de foguetes. Enquanto isso, ele não deve ser mais complicado do que esse trecho. Todos os créditos para esse cara

Como você descobrir a função de chamada em 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)]

Eu estou tentando endereço tanto a questão ea generosidade atual com esta questão.

A recompensa exige que o chamador ser obtido em estrita Modo, ea única maneira que eu posso ver este feito é referindo-se a uma função declarada fora de modo estrito.

Por exemplo, o seguinte é não-padrão, mas foi testado com anterior (29/03/2016) e corrente (01 de agosto de 2018) versões do Chrome, Edge e 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();

Se você realmente precisar da funcionalidade por algum motivo e quer que ele seja cross-browser compatível e não se preocupar para o material rigorosa e ser compatível, em seguida, passar um esta referência:

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
}

Eu acho o seguinte pedaço de código pode ser útil:

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

Executar o código:

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

Os olhares de registro como este:

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

Como nenhuma das respostas trabalhos anteriores como o que eu estava procurando (ficando apenas a última função chamada não uma função como uma string ou callstack) eu postar minha solução aqui para aqueles que são como eu e espero que este irá trabalhar para eles:

function getCallerName(func)
{
  if (!func) return "anonymous";
  let caller = func.caller;
  if (!caller) return "anonymous";
  caller = caller.toString();
  if (!caller.trim().startsWith("function")) return "anonymous";
  return caller.substring(0, caller.indexOf("(")).replace("function","");
}


//  Example of how to use "getCallerName" function

function Hello(){
console.log("ex1  =>  " + getCallerName(Hello));
}

function Main(){
Hello();

// another example
console.log("ex3  =>  " + getCallerName(Main));
}

Main();

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top