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());
}
arguments.callee.caller.name
получит имя функции.
'use strict';
может помочь.
arguments
МОЖЕТ быть доступным изнутри функции в строгом режиме, было бы глупо отрицать это. просто не из функции. аргументы извне. Кроме того, если у вас есть именованный аргумент, форма arguments [i] не будет отслеживать изменения, которые вы вносите в именованную версию внутри функции.
Вы можете найти всю трассировку стека, используя специфический для браузера код. Хорошо, что кто-то уже сделал это ; Вот код проекта на 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) получить больше, чем без кода всей функции.
И резюмируя остальные лучшие ответы (Пабло Кабрера, Нурдин и Грег Хьюгилл). Единственная кросс-браузерная и действительно безопасная вещь, которую вы можете использовать:
arguments.callee.caller.toString();
Который покажет код функции звонящего. К сожалению, этого недостаточно для меня, и именно поэтому я даю вам подсказки для StackTrace и функции вызывающей стороны Name (хотя они не являются кросс-браузерными).
Function.caller
в ответ @ Грег
Function.caller
однако не будет работать в строгом режиме.
Я знаю, что вы упомянули "в Javascript", но если целью является отладка, я думаю, что проще использовать инструменты разработчика вашего браузера. Вот как это выглядит в Chrome: просто бросьте отладчик, где вы хотите исследовать стек.
Подведем итоги (и проясним)
этот код:
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
.
Примечание: это вызывает бесконечный цикл на рекурсивных функциях.
Я обычно использую (new Error()).stack
в Chrome. Приятно то, что это также дает вам номера строк, где вызывающая сторона вызывала функцию. Недостатком является то, что он ограничивает длину стека до 10, поэтому я пришел на эту страницу в первую очередь.
(Я использую это для сбора callstacks в низкоуровневом конструкторе во время выполнения, для просмотра и отладки позже, поэтому установка точки останова не используется, так как она будет срабатывать тысячи раз)
'use strict';
на месте. Дали мне информацию, в которой я нуждался - спасибо!
Если вы не собираетесь запускать его в IE <11, тогда будет подходить console.trace () .
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
Вы можете использовать Function.Caller, чтобы получить вызывающую функцию. Старый метод, использующий аргумент arguments.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
Помните, что Function.caller нестандартный: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
Cannot access caller property of a strict mode function
Я бы сделал это:
function Hello() {
console.trace();
}
function Hello() {
alert(Hello.caller);
}
arguments.callee.caller.toString()
Это безопаснее в использовании, *arguments.callee.caller
так arguments.caller
как устарела ...
arguments.callee
также устарела в ES5 и удалена в строгом режиме.
arguments.callee
было плохим решением проблемы, которая теперь лучше решена developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Похоже, это довольно решенный вопрос, но недавно я обнаружил, что вызываемый объект не допускается в «строгом режиме», поэтому для собственного использования я написал класс, который будет получать путь от места его вызова. Это часть небольшой вспомогательной библиотеки, и если вы хотите использовать автономный код, измените смещение, используемое для возврата трассировки стека вызывающей стороны (используйте 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()
в консоли (не пробовал в файле), но, похоже, есть разумная идея. В любом случае следует проголосовать за видимость.
Попробуйте получить доступ к этому:
arguments.callee.caller.name
Просто консоль журнала вашей ошибки стека. Вы можете узнать, как вас зовут
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()
И в ES6, и в строгом режиме используйте следующую функцию, чтобы получить функцию Caller.
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])
Обратите внимание, что в приведенной выше строке будет сгенерировано исключение, если нет вызывающей стороны или нет предыдущего стека. Используйте соответственно.
console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
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 log with:', ...messages);
} else {
console.log(fnName(logLines[2]), 'called log with:', ...messages);
}
} else {
console.log(...messages);
}
}
function foo() {
log('hi', 'there');
}
(function main() {
foo();
}());
Я хотел добавить свою скрипку здесь для этого:
http://jsfiddle.net/bladnman/EhUm3/
Я проверял это хром, сафари и IE (10 и 8). Работает отлично. Имеет значение только 1 функция, поэтому, если вас пугает большая скрипка, читайте ниже.
Примечание: в этой скрипке довольно много моих собственных "шаблонов". Вы можете удалить все это и использовать сплит, если хотите. Это просто ультра-безопасный »набор функций, на которые я полагаюсь.
Там также есть шаблон "JSFiddle", который я использую для многих скрипок, чтобы просто быстро поиграть.
String.prototype.trim = trim;
Если вам просто нужно имя функции, а не код, и вы хотите независимое от браузера решение, используйте следующее:
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 / Androidname
, кажется, работает оленья кожа. Но 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();
Разные браузеры показывают стек в разных форматах строки:
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
in Error
. На самом деле это будет работать в тех случаях, когда callee
/ caller
подход не работает. Он также покажет вам контекст, то есть исходный файл и номер строки. Однако необходимо приложить усилия, чтобы сделать решение кроссплатформенным.
Обратите внимание, что вы не можете использовать Function.caller в Node.js, вместо этого используйте пакет caller-id . Например:
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 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.
arguments.callee
был осужден в течение многих лет .
Другой способ обойти эту проблему - просто передать имя вызывающей функции в качестве параметра.
Например:
function reformatString(string, callerName) {
if (callerName === "uid") {
string = string.toUpperCase();
}
return string;
}
Теперь вы можете вызвать функцию следующим образом:
function uid(){
var myString = "apples";
reformatString(myString, function.name);
}
В моем примере используется жестко закодированная проверка имени функции, но вы можете легко использовать оператор switch или какую-то другую логику, чтобы делать то, что вы хотите.
Насколько я знаю, у нас есть два пути для этого из данных источников, как это
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;
}
}
Думаю, у тебя есть ответ :).
Почему все приведенные выше решения выглядят как ракетостроение. Между тем, это не должно быть сложнее, чем этот фрагмент. Все кредиты этому парню
Как вы узнаете функцию вызова в 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)]
Я пытаюсь ответить и на этот вопрос, и на текущую награду.
Щедрость требует, чтобы вызывающий был получен в строгом режиме, и единственный способ увидеть это - обратиться к функции, объявленной вне строгого режима.
Например, следующее является нестандартным, но было протестировано с предыдущими (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();
Если вам действительно нужна функциональность по какой-то причине и вы хотите, чтобы она была совместима с разными браузерами, не беспокоились о строгих вещах и были совместимы с прямой версией, передайте следующую ссылку:
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