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
МОЖЛИ отримати доступ до якоїсь функції в суворому режимі, було б дурним це зневажити. тільки не з функції.аргументи ззовні. Крім того, якщо у вас є іменний аргумент, форма його аргументів [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 та функції виклику (ім'я для виклику) (хоча вони не є крос-браузером).
Function.caller
відповідь від @ Грега
Function.caller
Однак робота в суворому режимі не буде.
Я знаю, що ви згадали "в Javascript", але якщо мета налагодження, я думаю, що простіше просто скористатися інструментами для розробників вашого браузера. Ось як це виглядає в Chrome: Просто опустіть налагоджувач там, де ви хочете дослідити стек.
Щоб скласти резюме (і зробити його зрозумілішим) ...
цей код:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
еквівалентно цьому:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
Ясно, що перший біт є більш портативним, оскільки ви можете змінити назву функції, скажімо, з "Привіт" на "Ciao", і все-таки змусити цю роботу працювати.
В останньому, у випадку, якщо ви вирішите змінити назву викликаної функції (Привіт), вам доведеться змінити всі її виникнення :(
Ви можете отримати повний стек-трек:
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
Поки не телефонує null
.
Примітка: вона викликає нескінченний цикл на рекурсивних функціях.
Я зазвичай використовую (new Error()).stack
в Chrome. Приємно, що це також дає вам номери рядків, де абонент викликав функцію. Мінус у тому, що він обмежує довжину стека до 10, саме тому я зайшов на цю сторінку в першу чергу.
(Я використовую це для збору викликів викликів у конструкторі низького рівня під час виконання, для перегляду та налагодження пізніше, тому встановлення точки розриву не корисне, оскільки воно буде вдарене тисячі разів)
'use strict';
на місці. Дайте мені потрібну інформацію - дякую!
Якщо ви не збираєтеся запускати його в IE <11, тоді console.trace () підійде.
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
Ви можете використовувати Function.Caller, щоб отримати функцію дзвінка. Старий метод використання argument.caller вважається застарілим.
Наступний код ілюструє його використання:
function Hello() { return Hello.caller;}
Hello2 = function NamedFunc() { return NamedFunc.caller; };
function main()
{
Hello(); //both return main()
Hello2();
}
Примітки про застарілий argument.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() {
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/…
Схоже, це досить вирішене запитання, але нещодавно я з’ясував, що 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 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()
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();
}());
І в режимі ES6, і в строгому режимі скористайтеся наступним, щоб отримати функцію Caller
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])
Зауважте, що вищенаведений рядок буде винятком, якщо немає абонента або попереднього стека. Використовуйте відповідно.
console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
Я хотів додати тут свою загадку:
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 стек буде невизначений - вам потрібно скинути реальний виняток, щоб отримати стек.
Висновок: Можна визначити "головним" викликає "Привіт", використовуючи stack
" Error
об'єкт". Насправді він працюватиме у випадках, коли callee
/ caller
підхід не працює. Він також покаже вам контекст, тобто вихідний файл та номер рядка. Однак необхідні зусилля, щоб зробити рішення крос-платформою.
Зауважте, що ви не можете використовувати Function.caller в Node.js, замість цього використовуйте пакет call-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);
}
У моєму прикладі використовується чітко кодована перевірка імені функції, але ви можете легко використовувати оператор перемикання або якусь іншу логіку, щоб робити все, що вам потрібно.
Наскільки я знаю, у нас є два шляхи для цього з таких джерел, як
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