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

function main()
{
   Hello();
}

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

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

Я надеюсь, что это просто поможет вам в отладке. Изменение поведения в зависимости от вызывающего - плохая идея.

OJ. 11.11.2008 12:15

Когда это будет полезно для отладки?

Anderson Green 09.08.2012 23:31

@AndersonGreen, когда у вас есть, например, метод рендеринга шаблона по умолчанию и вы видите, что он вызывается дважды. Вместо того, чтобы копаться в тысячах LoC или усердно работать с отладчиком, вы можете просто увидеть, какой был стек в то время.

tkone 20.10.2012 23:04

чтобы увидеть трассировку стека, используйте console.trace () для chrome. хотя не знаю о других

lukas.pukenis 10.10.2013 21:36

Это не должно использоваться для «изменения» поведения (1-й комментарий). Подумайте о концепции промежуточного программного обеспечения, где вы можете просто проверить, вызывает ли вызывающий другой именованное промежуточное программное обеспечение ...

sebilasse 06.03.2014 13:25

@ lukas.pukenis Использование stacktracejs.com также может быть вариантом, кроссбраузерность, конечно, потому что это чистый Javascript, поэтому нет JQuery или другого зависимого.

m3nda 06.01.2016 08:40

Для отладки это также может быть полезно при работе с событиями. При остановке для трассировки вы фактически нарушаете цепочку событий, которые хотите проверить. Этот console.trace () спас мне день. Он работает в IE11, Firefox и Chrome.

Melanie 16.07.2016 00:38

Это также может быть полезно, если вам нужна полная трассировка стека: stackoverflow.com/questions/6715571/…

Enrique 10.08.2018 23:22
console.info((new Error()).stack.split("\n")[2].trim().split(" ")[1]) для ES6 или «строгий режим». Этот оператор вызывает исключение, если вызывающего абонента нет.
VanagaS 14.07.2019 04:17

Почему это плохая идея?

Jacob Schneider 28.07.2019 12:36
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
912
10
483 245
32
Перейти к ответу Данный вопрос помечен как решенный

Ответы 32

Ответ принят как подходящий
function Hello()
{
    alert("caller is " + Hello.caller);
}

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

Non-standard
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.


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

function Hello()
{
    alert("caller is " + arguments.callee.caller.toString());
}
arguments.callee.caller.name получит имя функции.
Rocket Hazmat 06.10.2010 00:16

он бросает arguments.callee.caller is null в приложение Mozilla (xulrunner 1.9.2)

The Student 04.04.2011 18:45

@Incognito, как вы, несомненно, уже догадались, любую функцию можно преобразовать в строку. Я вообще не могу придумать никаких трюков ... Источник.

Aaria Carter-Weir 04.08.2011 13:38

«Свойства 'вызывающий', 'вызываемый' и 'аргументы' не могут быть доступны для функций строгого режима или объектов аргументов для их вызовов» - они устарели в ES5 и удалены в строгом режиме.

ThatGuy 04.10.2011 05:39

arguments.callee.caller.name не работал у меня, поэтому, чтобы просто получить возвращаемое имя функции вызывающего абонента, я использовал это: 'arguments.callee.caller.toString (). split (' (') [0]'

Tim Sheiner 30.08.2012 22:12

Это будет работать, только если вы не используете строгий режим. Так что удаление 'use strict'; может помочь.

pvorb 09.04.2013 15:52

Хм, аргументы нельзя использовать в строгом режиме? Тогда как я могу использовать список переменных аргументов без него?

LGB 10.09.2013 20:39

Доступ к arguments МОЖЕТ быть доступен из функции в строгом режиме, было бы глупо отказываться от этого. просто не из функции. аргументов извне. Кроме того, если у вас есть именованный аргумент, его форма arguments [i] не будет отслеживать изменения, которые вы вносите в именованную версию внутри функции.

rvr_jon 08.11.2013 06:43

Этот метод устарел с тех пор, как этот пост был внесен в список в 2011 году. Теперь предпочтительным методом является Function.caller (по состоянию на 2015 год).

Greg 13.06.2015 05:52

@Greg У вас есть источник (например, URL-адрес) для этого?

inetphantom 11.03.2016 12:43

Это нестандартно (на данный момент), но URL-адрес: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

Daniel Lidström 16.03.2016 18:36
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Function.caller: Нестандартный Эта функция нестандартна и не входит в стандартную дорожку. Не используйте его на рабочих сайтах, выходящих в Интернет: он подойдет не для всех пользователей. Между реализациями также может быть большая несовместимость, и поведение может измениться в будущем.
egidiocs 09.05.2016 08:18

@RocketHazmat callee.name даст пустую строку, если функция анонимна.

Imad 10.10.2016 12:07

Важно отметить, что arguments.callee устарел и недоступен в строгом режиме. посмотрим, почему здесь: stackoverflow.com/questions/103598/…

Siddiqui Noor 09.03.2017 12:12
Function.caller не работает для большей части ES6: это запрещенное расширение для функций строгого режима, которые, если они определены, должны выдавать при доступе. И ES6 модули всегда в строгом режиме. Chrome V8 реализует это; caller есть только в функциях небрежного режима. Это по соображениям безопасности.
Orafu 03.11.2017 19:52

Всем, кто ищет более современное решение, которое работает в Typescript и фреймворках, таких как Angular, используйте console.info((new Error).stack);.

Rein Baarsma 28.06.2019 11:38

в моем случае он возвращает значение null

Devang Hingu 03.02.2020 16:02

@ReinBaarsma дает одну большую строку

Max Coplan 02.09.2020 02:03

@RocketHazmat старый комментарий поста, но спасибо! Действительно, «arguments.callee.caller.name» получит имя, и это очень поможет при поддержке старого сайта, где много событий «onclick» или «on-something ()» прикреплены к элементам, которые вызывают тот же хендлер! Часто исходный код передает только "this", что хорошо для наследования объекта, но НЕ может предлагать тип события! В новых браузерах доступно 'event' или хотя бы 'window.event', но есть исключения! Теперь, когда ни один из них недоступен, у меня есть план Б, поскольку тип события может быть получен из имени вызывающего абонента! ПОТРЯСАЮЩЕ!

Randy 04.12.2020 04:23

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

arguments.callee также устарел в ES5 и удаляется в строгом режиме.
nyuszika7h 04.05.2011 18:25

Есть ли альтернатива? Обновлено: arguments.callee был плохим решением проблемы, которая теперь решена лучше developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

Matthew 24.06.2014 12:32

Попробуйте получить доступ к этому:

arguments.callee.caller.name

Это был устарел много лет.

Dan Dascalescu 04.01.2019 04:41
function Hello() {
    alert(Hello.caller);
}

И просто для имени функции используйте Hello.caller.name

vanval 28.05.2014 00:30

такой же, как arguments.callee.caller.toString()

user2720864 20.01.2015 11:34

Это должен быть правильный ответ, по крайней мере, на 2016 год.

Daniel 24.03.2016 19:58

Это не соответствует стандарту, но будет работать с ECMAScript 5.

Obinna Nwakwue 26.03.2016 19:32

@ Дэниел: нет, не должно. См. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

Dan Dascalescu 04.01.2019 04:40

Подведем итоги (и сделаем это яснее) ...

этот код:

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

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

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

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

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

arguments.callee.caller всегда равен нулю в Chrome 25.0.1364.5 dev

Kokizzu 05.01.2013 09:28

Трассировки стека

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

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

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

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

    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}, но я не нашел никаких реальных улучшений, сделав это.

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


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

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

arguments.callee.caller.name

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


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

И резюмируя остальные лучшие ответы (Пабло Кабрера, Нурдин и Грег Хьюджилл). Единственная кроссбраузерная и действительно безопасная вещь, которую вы можете использовать:

arguments.callee.caller.toString();

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

возможно, вам стоит добавить Function.caller на @ Ответ Грега

Zach Lysobey 17.09.2015 18:30

Однако Function.caller не работает в строгом режиме.

Rickard Elimää 21.05.2019 12:35

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

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

Пока вызывающий абонент не будет null.

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

Извините за поздний ответ, но я не видел вашего комментария раньше; только для случая рекурсии это не работает, в других случаях должно работать.

ale5000 13.05.2016 22:47

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

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

Это был устарел много лет.

Dan Dascalescu 04.01.2019 04:42

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

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

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

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

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

Интересно, могли бы вы в некоторых случаях добавить «помощников» в качестве расширений для прототипа, например: String.prototype.trim = trim;

autistic 30.03.2016 12:06

Здесь все, кроме functionname, отделено от caller.toString() с помощью RegEx.

<!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>

это по-прежнему возвращает полное объявление метода

Maslow 26.02.2013 19:51

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

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.

Попробуйте это для рекурсивных функций.

daniel1426 01.05.2014 21:08
arguments.callee был устарел много лет.
Dan Dascalescu 04.01.2019 04:44

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

У меня не работает с function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a() в консоли (не пробовал в файле), но, похоже, у меня есть разумная идея. В любом случае должен быть одобрен для видимости.

ninjagecko 02.11.2014 13:45

Идея отличная. Я разбираюсь по-другому, но в приложениях nw.js это единственная идея, которая дает то, что я ищу.

Andrew Grothe 29.06.2015 18:48

Приведите пример вызова этой функции.

pd_au 20.06.2018 07:51

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

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

Это старый вопрос ... но это определенно самый современный способ сделать это на сегодняшний день.

markstewie 06.11.2015 01:41

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

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

Не могли бы вы добавить еще немного описания к предоставленному вами объяснению?

abarisone 07.05.2015 17:35

Это единственное, что я мог заставить работать, когда 'use strict'; установлен. Предоставил мне необходимую информацию - спасибо!

Jeremy Harris 30.06.2015 18:00

Что касается предела длины стека ... вы можете изменить это с помощью «Error.stackTraceLimit = Infinity».

Tom 07.04.2017 19:06

(новая ошибка ("StackLog")). stack.split ("\ n") упрощает чтение.

Teoman shipahi 13.10.2018 20:38

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

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

function Hello() { return Hello.caller;}

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

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

Примечания об устаревшем аргументе. Вызывающий: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

Имейте в виду, что Function.caller нестандартен: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller

Это правильный ответ в наши дни. Вы больше не можете использовать arguments.caller.callee. Хотелось бы, чтобы это переместили в начало, так как все остальное уже устарело.

coblr 30.06.2015 23:36

Кажется, это невозможно в строгом режиме? Cannot access caller property of a strict mode function

Zach Lysobey 16.09.2015 18:38

Function.caller у меня тоже не работал в строгом режиме. Кроме того, по данным MDN, function.caller нестандартен и не должен использоваться в продакшене. Однако это может сработать для отладки.

jkdev 21.09.2015 05:02

У меня не было проблем с нестандартным, если он работал в Node, но это просто недопустимо в строгом режиме (я тестировал на узле 6.10). То же самое и с аргументами. Я получаю сообщение об ошибке: '' 'вызывающий' и 'аргументы' являются ограниченными свойствами функции и не могут быть доступны в этом контексте. "

Tom 07.04.2017 17:40

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

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
}

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

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

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

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

Например:

function reformatString(string, callerName) {

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

    return string;
}

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

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

    reformatString(myString, function.name);
}

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

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

GrayedFox 04.03.2016 18:30

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

  1. arguments.caller

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

Думаю, у тебя есть ответ :).

Это был устарел много лет, и Function.caller не работает в строгом режиме.

Dan Dascalescu 04.01.2019 04:44

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

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

Например, следующее нестандартно, но было протестировано с предыдущими (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.info('Anonymous function called by ' + caller().name); })();
}

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

main();

Хороший хак, но не работает для Модули ES5, которые полностью находятся в строгом режиме.

Dan Dascalescu 04.01.2019 04:54

вот функция для получить полную трассировку стека:

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

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

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

Вот что я получаю при использовании этого: TypeError: свойства «вызывающий», «вызываемый» и «аргументы» могут быть недоступны для функций строгого режима или объектов аргументов для их вызовов. Есть идеи, как это сделать в строгом режиме?

hard_working_ant 29.05.2017 06:57

Я думаю, что следующий фрагмент кода может быть полезен:

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.info(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.info(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

Это ОЧЕНЬ ПОЛЕЗНО, потому что (во всяком случае в Chrome) сброс нового объекта Error () без изменений показывает информацию о файле / строке ИСТОЧНИКА (например, информацию о TypeScript). Однако ПОСЛЕ замены вы получите ФАКТИЧЕСКУЮ перенесенную информацию JavaScript. Понятия не имею, почему это происходит при простой замене строки, но это чистая случайность. Кроме того, с транспилированным кодом он показывает фактический URL-адрес, с которого был получен код, а не только имя модуля. Извлечение третьей строки вывода в любом случае может определить местоположение вызывающего абонента либо в исходном исходном коде, либо в перенесенном JavaScript.

BRebey 12.12.2020 04:12

Оба ответ Хейстюарта и JiarongWu ответ упомянули, что объект Error имеет доступ к stack.

Вот пример:

function main() {
  Hello();
}

function Hello() {
  var stack = new Error().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.info("Caller is:", caller_name)
  }
}

main();

В разных браузерах стек отображается в разных строковых форматах:

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)

Большинство браузеров устанавливают стек с var stack = (new Error()).stack. В Internet Explorer стек будет неопределенным - для получения стека необходимо создать реальное исключение.

Вывод: с помощью stack в объекте Error можно определить, что «основной» - это вызывающий «Hello». Фактически, это будет работать в тех случаях, когда подход callee / caller не работает. Он также покажет вам контекст, то есть исходный файл и номер строки. Однако необходимы усилия, чтобы сделать решение кроссплатформенным.

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

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

Это отлично работает! следует принять как правильный ответ, так как другие способы устарели \ больше не работают

Yuval Pruss 28.08.2019 10:08

Обновление 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.info(callerName, 'called log with:', ...messages);
    } else {
      console.info(fnName(logLines[2]), 'called log with:', ...messages);
    }
  } else {
    console.info(...messages);
  }
}

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

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

Это невероятно и ужасно.

Ian 01.07.2019 17:08

Я получил "foo call with: hi there", но фу не был вызван с "hi there", журнал был вызван с "hi there"

AndrewR 29.10.2019 18:25

Правильно, в грамматике сообщения об ошибке был "неуместный модификатор". Это означало, что «журнал был вызван из функции f, он хотел напечатать сообщение X», но как можно более кратко.

Rovanion 30.10.2019 09:06

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

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

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

sello()

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

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.info("ex1  =>  " + getCallerName(Hello));
}

function Main(){
Hello();

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

Main();
caller не работает в строгом режиме.
Dan Dascalescu 04.01.2019 04:53

@DanDascalescu, я не вижу в вопросе запроса на strict mode!

pouyan 17.01.2019 17:29

Приведение функции к строке для получения ее имени может быть очень медленным.

dy_ 29.07.2019 04:43

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

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

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

Чтобы получить вызываемого (текущее имя функции), используйте:

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

Обратите внимание, что вы не можете использовать Function.caller в Node.js, вместо этого используйте пакет идентификатор вызывающего абонента. Например:

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
    }
    */
}

У меня отлично работает, и вы можете выбрать, на сколько вы хотите вернуться в функциях:

function getCaller(functionBack= 0) {
    const back = functionBack * 2;
    const stack = new Error().stack.split('at ');
    const stackIndex = stack[3 + back].includes('C:') ? (3 + back) : (4 + back);
    const isAsync = stack[stackIndex].includes('async');
    let result;
    if (isAsync)
      result = stack[stackIndex].split(' ')[1].split(' ')[0];
    else
      result = stack[stackIndex].split(' ')[0];
    return result;
}

Другие вопросы по теме