function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Есть ли способ обнаружить стек вызовов вообще?
Обычно я использую (new Error()).stack в Chrome. Приятно, что это также дает номера строк, в которых вызывающая функция называется функцией. Недостатком является то, что он ограничивает длину стека до 10, поэтому я пришел на эту страницу в первую очередь.
(я использую это для сбора стоп-копов в низкоуровневом конструкторе во время выполнение, просмотр и отладка позже, поэтому установка точки останова не нужна, так как она будет ударяться тысячи раз)
Вы можете получить полную стек:
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
Пока не будет null.
Примечание: это вызывает бесконечный цикл для рекурсивных функций.
Безопаснее использовать *arguments.callee.caller, поскольку arguments.caller устарел ...
Попробуйте получить доступ к этому:
arguments.callee.caller.name
Если вы не собираетесь запускать его в IE & lt; 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: //developer.mozilla. org / en-US / docs / Web / JavaScript / Reference / Functions / arguments / caller
Знать Функция.caller нестандартна: https://developer.mozilla.org/en -US / документы / Web / JavaScript / Справочные материалы / Функции / аргументы / вызывающего абонента
Вы можете найти всю трассировку стека с использованием кода браузера. Хорошо, что кто-то уже сделал это; вот код проекта на GitHub.
Но не все новости хороши:
Очень медленно получить трассировку стека, поэтому будьте осторожны (прочтите это для большего). Вам нужно будет определить имена функций для трассировки стека, чтобы они были четкими. Потому что, если у вас есть такой код: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();
Что будет показано . Только кросс-браузер и действительно безопасная вещь, которую вы можете использовать: of функция вызывающего абонента. К сожалению, этого недостаточно для меня, и именно поэтому я даю вам советы для StackTrace и функции имени вызывающего абонента (хотя они не являются кросс-браузерами).
Я бы сделал это:
function Hello() {
console.trace();
}
Я знаю, что вы упомянули «в Javascript», но если цель отладки, я думаю, что проще использовать инструменты разработчика вашего браузера. Вот как это выглядит в Chrome: просто отпустите отладчик, где вы хотите исследовать стек.
Похоже, это довольно решенный вопрос, но я недавно узнал, что вызываемый не разрешен в «строгом режиме», поэтому для моего собственного использования я написал класс, который получит путь от того, где он вызывается. Это часть небольшой вспомогательной библиотеки, и если вы хотите использовать автономное изменение кода, смещение, используемое для возврата трассировки стека вызывающего (используйте 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() {
alert("caller is " + arguments.callee.caller.toString());
}
эквивалентен этому:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
Ясно первый бит более портативный, так как вы можете изменить имя функции, скажем, от «Hello» до «Ciao», и все равно заставить все работать.
В последнем случае, если вы решите реорганизовать имя вызываемой функции (Hello), вам придется изменить все ее вхождения :(
Насколько я знаю, у нас есть 2 способа для этого из таких источников:
arguments.callerfunction 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;
}
}
Подумайте, у вас есть ваш ответ:).
Здесь все, кроме 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>
Я пытаюсь решить этот вопрос и текущую щедрость с этим вопросом.
Баунти требует, чтобы вызывающий объект был получен в строгом режиме, и единственный способ, которым я могу это сделать, - это ссылаясь на функцию, объявленную вне строгого режима.
Например, следующее нестандартное, но было протестировано с предыдущими (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();
Я хотел добавить сюда свою скрипку:
http://jsfiddle.net/bladnman/EhUm3/
Я тестировал это хром, сафари и IE (10 и 8). Работает отлично. Есть только одна функция, которая имеет значение, поэтому, если вы боитесь большой скрипки, читайте ниже.
Примечание: в этой скрипке есть довольно много моего «шаблона». Вы можете удалить все это и использовать split, если хотите.
Существует также шаблон «JSFiddle», который я использую для многих скриптов, чтобы просто быстро возиться.
Почему все вышеперечисленные решения выглядят как ракетостроение. Между тем, это не должно быть сложнее, чем этот фрагмент. Все кредиты этому парню
Как узнать функцию звонящего в 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 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 или какую-то другую логику, чтобы делать то, что вы хотите там.
Я думаю, что следующая часть кода может быть полезна:
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
Если вам просто нужно имя функции, а не код, и вы хотите независимое от браузера решение, используйте следующее:
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]);
Если вам действительно нужна функциональность по какой-то причине и хотите, чтобы она была совместима с кросс-браузером, а не беспокоиться о строгих вещах и быть совместимой с переходом, выполните следующую ссылку:
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
}
Просто хочу сообщить вам, что на PhoneGap / Android функция name, похоже, не работает. Но arguments.callee.caller.toString() выполнит трюк.
Просто запустите журнал стека ошибок. Затем вы можете узнать, как вы называетесь
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()
Сообщение с 2018 года, когда доступ к caller запрещен:
Следующая функция, похоже, выполняет эту работу в Firefox 52 и Chrome 61, хотя ее реализация делает много предположений о формате ведения журнала два браузера и не должны использоваться для какой-либо временной отладки разработчиков, учитывая, что он генерирует исключение и, возможно, выполняет два регулярных выражения перед выполнением.
let fnNameMatcher = /([^(]+)@|at ([^(]+) \(/;
function fnName(str) {
let regexResult = fnNameMatcher.exec(str);
return regexResult[1] || regexResult[2];
}
export function log(...messages: any[]) {
let logLines = (new Error().stack).split('\n');
let callerName = fnName(logLines[1]);
if (callerName !== null) {
if (callerName !== 'log') {
console.log(callerName, ...messages);
} else {
console.log(fnName(logLines[2]), ...messages);
}
} else {
console.log(...messages);
}
}
Как вы уже сказали, решение должно быть программным, мое решение не является программным, но только для цели отладки вы можете использовать простой трюк, чтобы получить функцию звонящего в инструменте разработчика браузера.
Шаги:
Применить точку останова в вашей последней строке определения функции, которая выполняется хорошо. выполните свой код, когда вы достигнете точки останова, нажмите F10 / F11, так как он переместит вас на следующую строку, которая будет выполнена. Следующей строкой будет строка точно после строки, из которой была вызвана ваша функция. Таким образом вы можете отслеживать вызывающего абонента.ответ 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.
Заключение: Можно определить, что «main» - это вызывающий объект «Hello», используя stack в объект Error. Фактически он будет работать в случаях, когда подход callee / caller не работает. Он также покажет вам контекст, то есть исходный файл и номер строки. Однако требуется усилие для решения кросс-платформы.
здесь есть функция, чтобы получить полный стек:
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}