function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
¿Hay alguna manera de averiguar la pila de llamadas?
function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
¿Hay alguna manera de averiguar la pila de llamadas?
Respuestas:
function Hello()
{
alert("caller is " + Hello.caller);
}
Tenga en cuenta que esta característica no es estándar , de Function.caller
:
No estándar
Esta característica no es estándar y no está en una pista estándar. No lo use en sitios de producción orientados a la Web: no funcionará para todos los usuarios. También puede haber grandes incompatibilidades entre implementaciones y el comportamiento puede cambiar en el futuro.
La siguiente es la respuesta anterior de 2008, que ya no es compatible con Javascript moderno:
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
arguments.callee.caller.name
obtendrá el nombre de la función.
'use strict';
podría ayudar.
arguments
Se puede acceder desde una función en modo estricto, sería estúpido desaprobar eso. simplemente no de la función. argumentos del exterior. Además, si tiene un argumento con nombre, la forma de los argumentos [i] no rastreará los cambios que realice en la versión con nombre dentro de la función.
Puede encontrar todo el seguimiento de la pila utilizando el código específico del navegador. Lo bueno es que alguien ya lo hizo ; Aquí está el código del proyecto en GitHub .
Pero no todas las noticias son buenas:
Es muy lento obtener el seguimiento de la pila, así que tenga cuidado (lea esto para obtener más información).
Deberá definir nombres de funciones para que el seguimiento de la pila sea legible. Porque si tienes un código como este:
var Klass = function kls() {
this.Hello = function() { alert(printStackTrace().join('\n\n')); };
}
new Klass().Hello();
Google Chrome alertará ... kls.Hello ( ...
pero la mayoría de los navegadores esperarán un nombre de función justo después de la palabra clave function
y lo tratarán como una función anónima. Ni siquiera Chrome podrá usar el Klass
nombre si no le das el nombre kls
a la función.
Y, por cierto, puede pasar a la función printStackTrace la opción, {guess: true}
pero no encontré ninguna mejora real al hacerlo.
No todos los navegadores le brindan la misma información. Es decir, parámetros, columna de código, etc.
Por cierto, si solo desea el nombre de la función de llamada (en la mayoría de los navegadores, pero no IE) puede usar:
arguments.callee.caller.name
Pero tenga en cuenta que este nombre será el que aparece después de la function
palabra clave. No encontré ninguna manera (incluso en Google Chrome) para obtener más que eso sin obtener el código de toda la función.
Y resumiendo el resto de las mejores respuestas (por Pablo Cabrera, Nourdine y Greg Hewgill). Lo único que puede usar entre navegadores y realmente seguro es:
arguments.callee.caller.toString();
Que mostrará el código de la función de llamada. Lamentablemente, eso no es suficiente para mí, y es por eso que le doy consejos para StackTrace y el nombre de la función de llamada (aunque no son de navegador cruzado).
Function.caller
según la respuesta de @ Greg
Function.caller
No funcionará en modo estricto, sin embargo.
Sé que mencionó "en Javascript", pero si el propósito es la depuración, creo que es más fácil usar las herramientas de desarrollador de su navegador. Así es como se ve en Chrome: simplemente suelte el depurador donde desee investigar la pila.
Para recapitular (y hacerlo más claro) ...
este codigo:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
es equivalente a esto:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
Claramente, el primer bit es más portátil, ya que puede cambiar el nombre de la función, decir "Hola" a "Ciao", y aún así hacer que todo funcione.
En este último caso, en caso de que decida refactorizar el nombre de la función invocada (Hola), deberá cambiar todas sus apariciones :(
Puede obtener el seguimiento completo de la pila:
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
Hasta que llama es null
.
Nota: causa un bucle infinito en las funciones recursivas.
Yo suelo usar (new Error()).stack
en Chrome. Lo bueno es que esto también le da los números de línea donde la persona que llama llamó a la función. La desventaja es que limita la longitud de la pila a 10, por eso llegué a esta página en primer lugar.
(Estoy usando esto para recopilar pilas de llamadas en un constructor de bajo nivel durante la ejecución, para verlas y depurarlas más tarde, por lo que establecer un punto de interrupción no es útil, ya que será golpeado miles de veces)
'use strict';
esté en su lugar. Me dio la información que necesitaba, ¡gracias!
Si no va a ejecutarlo en IE <11, entonces console.trace () sería adecuado.
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
Puede usar Function.Caller para obtener la función de llamada. El antiguo método que usa argumento.caller se considera obsoleto.
El siguiente código ilustra su uso:
function Hello() { return Hello.caller;}
Hello2 = function NamedFunc() { return NamedFunc.caller; };
function main()
{
Hello(); //both return main()
Hello2();
}
Notas sobre argumentos obsoletos.caller: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller
Tenga en cuenta que Function.caller no es estándar: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
Cannot access caller property of a strict mode function
Yo haría esto:
function Hello() {
console.trace();
}
function Hello() {
alert(Hello.caller);
}
arguments.callee.caller.toString()
Es más seguro de usar *arguments.callee.caller
ya que arguments.caller
está en desuso ...
arguments.callee
también está en desuso en ES5 y se elimina en modo estricto.
arguments.callee
fue una mala solución a un problema que ahora se ha resuelto mejor developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Parece que esta es una pregunta bastante resuelta, pero recientemente descubrí que la persona que llama no está permitida en 'modo estricto', así que para mi propio uso escribí una clase que obtendrá la ruta desde donde se llama. Es parte de una pequeña biblioteca auxiliar y, si desea utilizar el código de forma independiente, cambie el desplazamiento utilizado para devolver el seguimiento de la pila de la persona que llama (use 1 en lugar 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()
en la consola (no lo he probado en un archivo), pero parece tener una idea razonable. Debería ser votado de todos modos para mayor visibilidad.
Intenta acceder a esto:
arguments.callee.caller.name
Solo consola registre su pila de errores. Entonces puedes saber cómo te llaman
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()
Tanto en ES6 como en modo estricto, use lo siguiente para obtener la función de llamada
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])
Tenga en cuenta que, la línea anterior arrojará una excepción, si no hay llamador o no hay una pila anterior. Usar en consecuencia.
console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
caller
está prohibido en modo estricto . Aquí hay una alternativa usando la Error
pila (no estándar) .
La siguiente función parece hacer el trabajo en Firefox 52 y Chrome 61-71, aunque su implementación hace muchas suposiciones sobre el formato de registro de los dos navegadores y debe usarse con precaución, dado que arroja una excepción y posiblemente ejecuta dos expresiones regulares. coincidencias antes de hacerse.
'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();
}());
Quería agregar mi violín aquí para esto:
http://jsfiddle.net/bladnman/EhUm3/
Probé esto es Chrome, Safari e IE (10 y 8). Funciona bien. Solo hay 1 función que importa, así que si te asusta el gran violín, lee a continuación.
Nota: Hay una buena cantidad de mi propio "repetitivo" en este violín. Puede eliminar todo eso y usar divisiones si lo desea. Es solo un "conjunto de funciones ultra seguro" en el que he llegado a confiar.
También hay una plantilla "JSFiddle" que utilizo para muchos violines para simplemente tocar el violín rápidamente.
String.prototype.trim = trim;
Si solo desea el nombre de la función y no el código, y desea una solución independiente del navegador, use lo siguiente:
var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];
Tenga en cuenta que lo anterior devolverá un error si no hay una función de llamada ya que no hay ningún elemento [1] en la matriz. Para evitarlo, use lo siguiente:
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ólo quiero hacerle saber que en PhoneGap / androide del name
no se parece estar funcionando. Pero arguments.callee.caller.toString()
hará el truco.
Aquí, todo menos el functionname
es eliminado caller.toString()
, con 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>
Aquí hay una función para obtener el stacktrace completo :
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
La respuesta de heystewart y la respuesta de JiarongWu mencionaron que el Error
objeto tiene acceso a stack
.
Aquí hay un ejemplo:
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();
Los diferentes navegadores muestran la pila en diferentes formatos de cadena:
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)
La mayoría de los navegadores configurarán la pila con var stack = (new Error()).stack
. En Internet Explorer, la pila estará indefinida: debe lanzar una excepción real para recuperar la pila.
Conclusión: Es posible determinar que "main" es la persona que llama a "Hello" usando el stack
en el Error
objeto. De hecho, funcionará en los casos en que el enfoque callee
/ caller
no funcione. También le mostrará el contexto, es decir, el archivo fuente y el número de línea. Sin embargo, se requiere un esfuerzo para hacer que la solución sea multiplataforma.
Tenga en cuenta que no puede usar Function.caller en Node.js, use el paquete caller-id en su lugar. Por ejemplo:
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
}
*/
}
Prueba el siguiente 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;
}
Trabajó para mí en Firefox-21 y Chromium-25.
arguments.callee
ha quedado en desuso por muchos años .
Otra forma de evitar este problema es simplemente pasar el nombre de la función de llamada como parámetro.
Por ejemplo:
function reformatString(string, callerName) {
if (callerName === "uid") {
string = string.toUpperCase();
}
return string;
}
Ahora, podría llamar a la función de esta manera:
function uid(){
var myString = "apples";
reformatString(myString, function.name);
}
Mi ejemplo utiliza una verificación codificada del nombre de la función, pero podría usar fácilmente una instrucción de cambio o alguna otra lógica para hacer lo que quiera allí.
Hasta donde yo sé, tenemos dos formas para esto de fuentes 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;
}
}
Creo que tienes tu respuesta :).
Por qué todas las soluciones anteriores parecen una ciencia espacial. Mientras tanto, no debería ser más complicado que este fragmento. Todos los créditos a este chico
¿Cómo se encuentra la función de llamada en 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)]
Estoy tratando de abordar la pregunta y la recompensa actual con esta pregunta.
La recompensa requiere que la persona que llama se obtenga en modo estricto , y la única forma en que puedo ver esto es refiriéndose a una función declarada fuera del modo estricto.
Por ejemplo, lo siguiente no es estándar, pero se ha probado con versiones anteriores (29/03/2016) y actuales (1 de agosto de 2018) de Chrome, Edge y 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();
Si realmente necesita la funcionalidad por alguna razón y desea que sea compatible con todos los navegadores y no se preocupe por cosas estrictas y sea compatible con versiones posteriores, pase esta referencia:
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
}
Creo que el siguiente código puede 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);
}
Ejecute el 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();
El registro se ve así:
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