function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Есть ли способ узнать стек вызовов?
function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Есть ли способ узнать стек вызовов?
function Hello()
{
alert("caller is " + Hello.caller);
}
Обратите внимание, что эта функция нестандартна из Function.caller
:
Нестандартный
Эта функция является нестандартной и не соответствует стандартам. Не используйте его на рабочих сайтах, выходящих в Интернет: он не будет работать для каждого пользователя. Также могут быть большие несовместимости между реализациями, и поведение может измениться в будущем.
Ниже приводится старый ответ 2008 года, который больше не поддерживается в современном Javascript:
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
Вы можете найти всю трассировку стека, используя код, специфичный для браузера. Хорошая вещь кто-то уже сделал это; Вот код проекта на 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 и имени функции звонящего (хотя они не являются кросс-браузерами).
Повторить (и сделать его более ясным) ...
этот код:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
эквивалентно этому:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
Очевидно, что первый бит более портативен, так как вы можете изменить имя функции, скажем, от «Hello» до «Ciao», и все равно заставить все работать.
В последнем случае, если вы решите реорганизовать имя вызываемой функции (Hello), вам придется изменить все ее вхождения :(
Вы можете получить полную стек:
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
До вызова null
.
Примечание: это вызывает бесконечный цикл для рекурсивных функций.
Я знаю, что вы упомянули «в Javascript», но если цель отладки, я думаю, что проще использовать инструменты разработчика вашего браузера. Вот как это выглядит в Chrome: Просто отпустите отладчик, где вы хотите исследовать стек.
Обычно я использую (new Error()).stack
в Chrome.
Приятно, что это также дает номера строк, в которых вызывающая функция называется функцией. Недостатком является то, что он ограничивает длину стека до 10, поэтому я пришел на эту страницу в первую очередь.
(я использую это, чтобы собирать вызовы в низкоуровневом конструкторе во время выполнения, просматривать и отлаживать позже, поэтому установка точки останова не нужна, так как она будет ударяться тысячи раз)
Если вы не собираетесь запускать его в IE <11, тогда будет подходить console.trace().
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
Вы можете использовать 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
Безопаснее использовать *arguments.callee.caller
, поскольку arguments.caller
устарел ...
function Hello() {
alert(Hello.caller);
}
Похоже, это довольно решенный вопрос, но я недавно узнал, что 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('.');
};
}
Я бы сделал это:
function Hello() {
console.trace();
}
Попробуйте воспользоваться этим:
arguments.callee.caller.name
Просто консоль журнала вашей ошибки стека. Вы можете узнать, как вас зовут
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()
Я хотел добавить свою скрипку здесь для этого:
http://jsfiddle.net/bladnman/EhUm3/
Я тестировал это хром, сафари и IE (10 и 8). Работает отлично. Имеет значение только 1 функция, поэтому, если вас пугает большая скрипка, читайте ниже.
Примечание: в этой скрипке довольно много моих собственных "шаблонов". Вы можете удалить все это и использовать split, если хотите. Это просто ультра-безопасный "набор функций, на которые я пришел, чтобы положиться.
Там также есть шаблон "JSFiddle", который я использую для многих скрипок, чтобы просто быстро играть.
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();
}());
Если вам просто нужно имя функции, а не код, и вы хотите независимое от браузера решение, используйте следующее:
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]);
Просто хочу сообщить, что PhoneGap/Android name
, похоже, не работает. Но arguments.callee.caller.toString()
сделает трюк.
Здесь все, кроме 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>
здесь есть функция получить полный стек:
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
ответ 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();
Попробуйте использовать следующий код:
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.
Другой способ решения этой проблемы - просто передать имя вызывающей функции в качестве параметра.
Например:
function reformatString(string, callerName) {
if (callerName === "uid") {
string = string.toUpperCase();
}
return string;
}
Теперь вы можете вызвать функцию следующим образом:
function uid(){
var myString = "apples";
reformatString(myString, function.name);
}
В моем примере используется жестко закодированная проверка имени функции, но вы можете легко использовать оператор switch или какую-то другую логику, чтобы делать то, что вы там хотите.
Насколько я знаю, у нас есть 2 способа для этого из таких источников, как это -
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;
}
}
Подумайте, у вас есть свой ответ:).
Я пытаюсь ответить и на этот вопрос, и на текущую награду.
Для получения награды требуется, чтобы вызывающий был получен в строгом режиме, и единственный способ увидеть это - обратиться к функции, объявленной вне строгого режима.
Например, следующее является нестандартным, но было протестировано с предыдущими (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();
Почему все вышеперечисленные решения выглядят как ракетостроение. Между тем, это не должно быть сложнее, чем этот фрагмент. Все кредиты этому парню
Как вы узнаете Функция вызывающего абонента в 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)]
Если вам действительно нужна функциональность по какой-то причине и вы хотите, чтобы она была совместима с кросс-браузером, а не беспокоиться о строгих вещах и быть совместимой с переходом, выполните следующую ссылку:
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
}
Я думаю, что следующая часть кода может быть полезна:
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
Поскольку ни один из предыдущих ответов не работает так, как я искал (получение только последней вызывающей функции, а не функции в виде строки или 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();
И в ES6, и в строгом режиме используйте следующую функцию, чтобы получить функцию Caller.
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])
Обратите внимание, что в приведенной выше строке будет сгенерировано исключение, если нет вызывающей стороны или нет предыдущего стека. Используйте соответственно.