Как узнать функцию звонящего в JavaScript?

function main()
{
   Hello();
}

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

Есть ли способ узнать стек вызовов?

Ответ 1

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

Обратите внимание, что эта функция нестандартна из Function.caller:

Нестандартный
Эта функция является нестандартной и не соответствует стандартам. Не используйте его на рабочих сайтах, выходящих в Интернет: он не будет работать для каждого пользователя. Также могут быть большие несовместимости между реализациями, и поведение может измениться в будущем.


Ниже приводится старый ответ 2008 года, который больше не поддерживается в современном Javascript:

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

Ответ 2

StackTrace

Вы можете найти всю трассировку стека, используя код, специфичный для браузера. Хорошая вещь кто-то уже сделал это; Вот код проекта на GitHub.

Но не все новости хороши:

  • Очень медленно получить трассировку стека, поэтому будьте осторожны (прочитайте this для более).

  • Вам нужно будет определить имена функций для отслеживания трассировки стека. Потому что, если у вас есть такой код:

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

    Google Chrome сообщит ... kls.Hello ( ..., но большинство браузеров ожидают имя функции сразу после ключевого слова function и будут рассматривать его как анонимную функцию. Даже Chrome не сможет использовать имя Klass, если вы не дадите функции kls.

    И, кстати, вы можете перейти к функции printStackTrace с параметром {guess: true}, но я не нашел реального улучшения, выполнив это.

  • Не все браузеры предоставляют вам ту же информацию. То есть параметры, кодовый столбец и т.д.

<ч>

Имя функции вызывающего абонента

Кстати, если вам нужно только имя функции вызывающего абонента (в большинстве браузеров, но не в IE), вы можете использовать:

arguments.callee.caller.name

Но обратите внимание, что это имя будет после ключевого слова function. Я не нашел пути (даже в Google Chrome), чтобы получить больше, чем без кода всей функции.

<ч>

Код функции вызывающего абонента

И подводя итог остальным лучшим ответам (Pablo Cabrera, nourdine и Greg Hewgill). Единственный кросс-браузер и действительно безопасная вещь, которую вы можете использовать:

arguments.callee.caller.toString();

Будет отображаться код функции вызывающего абонента. К сожалению, этого недостаточно для меня, и именно поэтому я даю вам советы для StackTrace и имени функции звонящего (хотя они не являются кросс-браузерами).

Ответ 3

Повторить (и сделать его более ясным) ...

этот код:

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

эквивалентно этому:

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

Очевидно, что первый бит более портативен, так как вы можете изменить имя функции, скажем, от «Hello» до «Ciao», и все равно заставить все работать.

В последнем случае, если вы решите реорганизовать имя вызываемой функции (Hello), вам придется изменить все ее вхождения :(

Ответ 4

Вы можете получить полную стек:

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

До вызова null.

Примечание: это вызывает бесконечный цикл для рекурсивных функций.

Ответ 5

Я знаю, что вы упомянули «в Javascript», но если цель отладки, я думаю, что проще использовать инструменты разработчика вашего браузера. Вот как это выглядит в Chrome: введите описание изображения здесь Просто отпустите отладчик, где вы хотите исследовать стек.

Ответ 6

Обычно я использую (new Error()).stack в Chrome. Приятно, что это также дает номера строк, в которых вызывающая функция называется функцией. Недостатком является то, что он ограничивает длину стека до 10, поэтому я пришел на эту страницу в первую очередь.

(я использую это, чтобы собирать вызовы в низкоуровневом конструкторе во время выполнения, просматривать и отлаживать позже, поэтому установка точки останова не нужна, так как она будет ударяться тысячи раз)

Ответ 7

Если вы не собираетесь запускать его в IE <11, тогда будет подходить console.trace().

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

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

Ответ 8

Вы можете использовать Function.Caller для вызова вызывающей функции. Старый метод, использующий аргумент.caller, считается устаревшим.

Следующий код иллюстрирует его использование:

function Hello() { return Hello.caller;}

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

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

Заметки об устаревшем аргументе.caller: https: // разработчик. mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

Знать, что функция.caller нестандартна: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller

Ответ 9

Безопаснее использовать *arguments.callee.caller, поскольку arguments.caller устарел ...

Ответ 10

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

Ответ 11

Похоже, это довольно решенный вопрос, но я недавно узнал, что Callee не разрешено в «жестком режиме», поэтому для моего собственного использования я написал класс, который получит путь от того, где он вызывается. Это часть небольшой вспомогательной библиотеки, и если вы хотите использовать автономное изменение кода, Смещение, используемое для возврата трассировки стека вызывающего абонента (используйте 1 вместо 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('.');
  };
}

Ответ 12

Я бы сделал это:

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

Ответ 13

Попробуйте воспользоваться этим:

arguments.callee.caller.name

Ответ 14

Просто консоль журнала вашей ошибки стека. Вы можете узнать, как вас зовут

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

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

sello()

Ответ 15

Я хотел добавить свою скрипку здесь для этого:

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

Я тестировал это хром, сафари и IE (10 и 8). Работает отлично. Имеет значение только 1 функция, поэтому, если вас пугает большая скрипка, читайте ниже.

Примечание: в этой скрипке довольно много моих собственных "шаблонов". Вы можете удалить все это и использовать split, если хотите. Это просто ультра-безопасный "набор функций, на которые я пришел, чтобы положиться.

Там также есть шаблон "JSFiddle", который я использую для многих скрипок, чтобы просто быстро играть.

Ответ 16

2018 Обновление

caller запрещен в строгом режиме. Вот альтернатива, использующая (нестандартный) стек Error.

Следующая функция, кажется, делает работу в Firefox 52 и Chrome 61-71, хотя ее реализация делает много предположений о формате регистрации двух браузеров и должна использоваться с осторожностью, учитывая, что она выдает исключение и, возможно, выполняет два регулярных выражения соответствия, прежде чем быть сделано.

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

Ответ 17

Если вам просто нужно имя функции, а не код, и вы хотите независимое от браузера решение, используйте следующее:

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

Обратите внимание, что приведенное выше вернет ошибку, если нет функции вызова, поскольку в массиве нет элемента [1]. Чтобы обойти, используйте следующее:

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

Ответ 18

Просто хочу сообщить, что PhoneGap/Android name, похоже, не работает. Но arguments.callee.caller.toString() сделает трюк.

Ответ 19

Здесь все, кроме functionname, удаляется из caller.toString() с помощью 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>

Ответ 20

здесь есть функция получить полный стек:

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

Ответ 21

ответ heystewart и Ответ JiarongWu оба упоминал, что объект Error имеет доступ к stack.

Вот пример:

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

Ответ 22

Попробуйте использовать следующий код:

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

Работала для меня в Firefox-21 и Chromium-25.

Ответ 23

Другой способ решения этой проблемы - просто передать имя вызывающей функции в качестве параметра.

Например:

function reformatString(string, callerName) {

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

    return string;
}

Теперь вы можете вызвать функцию следующим образом:

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

    reformatString(myString, function.name);
}

В моем примере используется жестко закодированная проверка имени функции, но вы можете легко использовать оператор switch или какую-то другую логику, чтобы делать то, что вы там хотите.

Ответ 24

Насколько я знаю, у нас есть 2 способа для этого из таких источников, как это -

  • arguments.caller

    function whoCalled()
    {
        if (arguments.caller == null)
           console.log('I was called from the global scope.');
        else
           console.log(arguments.caller + ' called me!');
    }
    
  • 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;
        }
    }
    

Подумайте, у вас есть свой ответ:).

Ответ 25

Я пытаюсь ответить и на этот вопрос, и на текущую награду.

Для получения награды требуется, чтобы вызывающий был получен в строгом режиме, и единственный способ увидеть это - обратиться к функции, объявленной вне строгого режима.

Например, следующее является нестандартным, но было протестировано с предыдущими (29/03/2016) и текущими (1 августа 2018 года) версиями Chrome, Edge и 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();

Ответ 26

Почему все вышеперечисленные решения выглядят как ракетостроение. Между тем, это не должно быть сложнее, чем этот фрагмент. Все кредиты этому парню

Как вы узнаете Функция вызывающего абонента в 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)]

Ответ 27

Если вам действительно нужна функциональность по какой-то причине и вы хотите, чтобы она была совместима с кросс-браузером, а не беспокоиться о строгих вещах и быть совместимой с переходом, выполните следующую ссылку:

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
}

Ответ 28

Я думаю, что следующая часть кода может быть полезна:

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

Выполнить код:

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

Журнал выглядит следующим образом:

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

Ответ 29

Поскольку ни один из предыдущих ответов не работает так, как я искал (получение только последней вызывающей функции, а не функции в виде строки или callstack), я публикую здесь свое решение для тех, кто похож на меня, и надеюсь, что это сработает для них:

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

Ответ 30

И в ES6, и в строгом режиме используйте следующую функцию, чтобы получить функцию Caller.

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

Обратите внимание, что в приведенной выше строке будет сгенерировано исключение, если нет вызывающей стороны или нет предыдущего стека. Используйте соответственно.