Как вы узнаете функцию вызова в JavaScript? - PullRequest
800 голосов
/ 11 ноября 2008
function main()
{
   Hello();
}

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

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

Ответы [ 29 ]

16 голосов
/ 04 марта 2014

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

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

function Hello() {
  console.trace();
}
11 голосов
/ 11 ноября 2008

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

arguments.callee.caller.name
10 голосов
/ 14 марта 2018

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

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

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

sello()
7 голосов
/ 07 сентября 2012

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

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

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

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

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

6 голосов
/ 26 февраля 2018

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();
}());
6 голосов
/ 15 марта 2012

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

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]);
5 голосов
/ 08 апреля 2014

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

4 голосов
/ 13 июля 2017

ответ 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();

Разные браузеры показывают стек в разных форматах:

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 стек не определен - вам нужно создать реальное исключение для извлечения стека.

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

4 голосов
/ 13 апреля 2016

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

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