function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Existe uma maneira de descobrir a pilha de chamadas?
function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Existe uma maneira de descobrir a pilha de chamadas?
Respostas:
function Hello()
{
alert("caller is " + Hello.caller);
}
Observe que esse recurso não é padrão , de Function.caller
:
Não padrão
Este recurso não é padrão e não está em uma faixa de padrões. Não o use em sites de produção voltados para a Web: ele não funcionará para todos os usuários. Também pode haver grandes incompatibilidades entre implementações e o comportamento pode mudar no futuro.
A seguir está a resposta antiga de 2008, que não é mais suportada no Javascript moderno:
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
arguments.callee.caller.name
obterá o nome da função.
'use strict';
pode ajudar.
arguments
PODE ser acessado de dentro de uma função no modo estrito, seria estúpido depreciar isso. apenas não da função. argumentos do lado de fora. Além disso, se você tiver um argumento nomeado, a forma de argumentos [i] dele não rastreará as alterações feitas na versão nomeada dentro da função.
Você pode encontrar todo o rastreamento de pilha usando o código específico do navegador. O bom é que alguém já conseguiu ; Aqui está o código do projeto no GitHub .
Mas nem todas as notícias são boas:
É muito lento para obter o rastreamento da pilha, portanto, tenha cuidado (leia isto para mais).
Você precisará definir os nomes das funções para que o rastreamento da pilha seja legível. Porque se você tiver um código como este:
var Klass = function kls() {
this.Hello = function() { alert(printStackTrace().join('\n\n')); };
}
new Klass().Hello();
O Google Chrome alerta, ... kls.Hello ( ...
mas a maioria dos navegadores espera um nome de função logo após a palavra-chave function
e o trata como uma função anônima. Nem mesmo o Chrome poderá usar o Klass
nome se você não der o nomekls
à função.
E, a propósito, você pode passar para a função printStackTrace a opção, {guess: true}
mas não encontrei nenhuma melhoria real ao fazer isso.
Nem todos os navegadores fornecem as mesmas informações. Ou seja, parâmetros, coluna de código etc.
A propósito, se você deseja apenas o nome da função de chamada (na maioria dos navegadores, mas não no IE), pode usar:
arguments.callee.caller.name
Mas observe que esse nome será o nome da function
palavra - chave. Não encontrei nenhuma maneira (mesmo no Google Chrome) de obter mais do que isso sem obter o código de toda a função.
E resumindo o restante das melhores respostas (de Pablo Cabrera, nourdine e Greg Hewgill). A única coisa que você pode usar em vários navegadores e realmente segura é:
arguments.callee.caller.toString();
O que mostrará o código da função de chamada. Infelizmente, isso não é suficiente para mim, e é por isso que eu dou dicas para o StackTrace e a função de chamada Name (embora eles não sejam entre navegadores).
Function.caller
per @ resposta de Greg
Function.caller
no entanto, não funcionará no modo estrito.
Sei que você mencionou "em Javascript", mas se o objetivo é depurar, acho mais fácil usar as ferramentas de desenvolvedor do seu navegador. É assim que fica no Chrome: basta soltar o depurador no local em que deseja investigar a pilha.
Para recapitular (e torná-lo mais claro) ...
este código:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
é equivalente a isso:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
Claramente, o primeiro bit é mais portátil, já que você pode alterar o nome da função, digitar "Hello" para "Ciao" e ainda assim fazer com que tudo funcione.
Neste último caso você decida refatorar o nome da função invocada (Hello), será necessário alterar todas as ocorrências :(
Você pode obter o stacktrace completo:
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
Até o chamador estar null
.
Nota: causa um loop infinito em funções recursivas.
Eu costumo usar (new Error()).stack
no Chrome. O bom é que isso também fornece os números de linha em que o chamador chamou a função. A desvantagem é que limita o comprimento da pilha a 10, e é por isso que cheguei a esta página em primeiro lugar.
(Estou usando isso para coletar pilhas de chamadas em um construtor de baixo nível durante a execução, para exibir e depurar mais tarde, portanto, definir um ponto de interrupção não é útil, pois será atingido milhares de vezes)
'use strict';
estiver no local. Deu-me as informações de que precisava - obrigado!
Se você não for executá-lo no IE <11, o console.trace () será adequado.
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
Você pode usar o Function.Caller para obter a função de chamada. O método antigo usando o argumento.caller é considerado obsoleto.
O código a seguir ilustra 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 de que Function.caller não é padrão: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
Cannot access caller property of a strict mode function
Eu faria isso:
function Hello() {
console.trace();
}
function Hello() {
alert(Hello.caller);
}
arguments.callee.caller.toString()
É mais seguro de usar, *arguments.callee.caller
pois arguments.caller
está obsoleto ...
arguments.callee
também foi descontinuado no ES5 e removido no modo estrito.
arguments.callee
foi uma solução ruim para um problema que agora foi melhor resolvido developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Parece que esta é uma pergunta bastante resolvida, mas recentemente descobri que o chamado não é permitido no 'modo estrito'; portanto, para meu próprio uso, escrevi uma classe que obterá o caminho de onde é chamada. Faz parte de uma pequena biblioteca auxiliar e, se você quiser usar o código independente, altere o deslocamento usado para retornar o rastreamento de pilha do chamador (use 1 em vez de 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('.');
};
}
function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a()
no console (não tentei em um arquivo), mas parece ter uma ideia razoável. Deve ser votado de qualquer maneira para ter visibilidade.
Tente acessar isso:
arguments.callee.caller.name
Apenas console registre sua pilha de erros. Você pode saber como está sendo chamado
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()
Nos modos ES6 e Rigoroso, use o seguinte para obter a função Chamador
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])
Observe que a linha acima lançará uma exceção, se não houver chamador ou pilha anterior. Use de acordo.
console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
caller
é proibido no modo estrito . Aqui está uma alternativa usando a Error
pilha (não padrão) .
A função a seguir parece fazer o trabalho no Firefox 52 e no Chrome 61-71, embora sua implementação faça muitas suposições sobre o formato de log dos dois navegadores e deva ser usada com cautela, pois gera uma exceção e possivelmente executa duas regex correspondências antes de serem feitas.
'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();
}());
Eu queria adicionar meu violino aqui para isso:
http://jsfiddle.net/bladnman/EhUm3/
Eu testei isso é chrome, safari e IE (10 e 8). Funciona bem. Há apenas uma função que importa, portanto, se você se assusta com o violino, leia abaixo.
Nota: Há uma boa quantidade do meu próprio "clichê" neste violino. Você pode remover tudo isso e usar divisões, se quiser. É apenas um conjunto "ultra-seguro" de funções nas quais confiei.
Há também um modelo "JSFiddle" que eu uso para muitos violinos para mexer rapidamente.
String.prototype.trim = trim;
Se você deseja apenas o nome da função e não o código, e deseja uma solução independente do navegador, use o seguinte:
var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];
Observe que o descrito acima retornará um erro se não houver função de chamada, pois não há elemento [1] na matriz. Para contornar, use o abaixo:
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 no PhoneGap / Android o name
parece não estar funcionando. Mas arguments.callee.caller.toString()
vai fazer o truque.
Aqui, tudo, exceto o, functionname
é retirado caller.toString()
, com o 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 está uma função para obter o stacktrace completo :
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
A resposta de heystewart e a resposta de JiarongWu mencionaram que o Error
objeto tem acesso aostack
.
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();
Navegadores diferentes mostram a pilha em diferentes formatos de sequência:
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 definirá a pilha com var stack = (new Error()).stack
. No Internet Explorer, a pilha será indefinida - é necessário lançar uma exceção real para recuperar a pilha.
Conclusão: É possível determinar que "principal" é o responsável pela chamada "Olá" usando stack
o Error
objeto De fato, funcionará nos casos em que a abordagem callee
/ caller
não funcionar. Também mostrará o contexto, ou seja, arquivo de origem e número da linha. No entanto, é necessário esforço para tornar a solução entre plataformas.
Observe que você não pode usar o Function.caller no Node.js, use o pacote caller-id . Por exemplo:
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
}
*/
}
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;
}
Trabalhou para mim no Firefox-21 e Chromium-25.
arguments.callee
foi descontinuado por muitos anos .
Outra maneira de contornar esse 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ê pode chamar a função assim:
function uid(){
var myString = "apples";
reformatString(myString, function.name);
}
Meu exemplo usa uma verificação codificada do nome da função, mas você pode facilmente usar uma instrução switch ou alguma outra lógica para fazer o que deseja lá.
Até onde eu sei, temos duas maneiras para isso, de fontes dadas como esta-
function whoCalled()
{
if (arguments.caller == null)
console.log('I was called from the global scope.');
else
console.log(arguments.caller + ' called me!');
}
function myFunc()
{
if (myFunc.caller == null) {
return 'The function was called from the top!';
}
else
{
return 'This function\'s caller was ' + myFunc.caller;
}
}
Acho que você tem a sua resposta :).
Por que todas as soluções acima parecem uma ciência de foguetes. Enquanto isso, não deve ser mais complicado que esse trecho. Todos os créditos para esse cara
Como você descobre 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)]
Estou tentando abordar a questão e a recompensa atual com essa pergunta.
A recompensa requer que o chamador seja obtido no modo estrito , e a única maneira de ver isso é fazendo referência a uma função declarada fora do modo estrito.
Por exemplo, o seguinte não é padrão, mas foi testado nas versões anterior (29/03/2016) e atual (1º de agosto de 2018) 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 precisa da funcionalidade por algum motivo e deseja que ela seja compatível com vários navegadores, não se preocupe com coisas estritas e seja compatível com a frente, passe 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
}
Acho que 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);
}
Execute 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();
O log fica assim:
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