Как узнать вызывающую функцию в JavaScript, когда включено строгое использование?

Можно ли увидеть вызывающего/вызывающего функцию, когда use strict включен?

'use strict';

function jamie (){
    console.info(arguments.callee.caller.name);
    //this will output the below error
    //uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
};

function jiminyCricket (){
   jamie();
}

jiminyCricket ();


person Jamie Hutber    schedule 11.04.2015    source источник
comment
В общем (за очень немногими исключениями) если вы хотите сделать это - вы делаете что-то не так. Попробуйте объяснить настоящую проблему, которую вы хотите решить с помощью этого кода.   -  person zerkms    schedule 11.04.2015
comment
Альтернативы нет. Рекомендуемый способ — использовать имя функции напрямую, например jamie.name // jamie. Но имена функций часто не имеют значения, кроме как для отладки, они не имеют значения в вашем коде, и полагаться на эту функциональность для чего-то другого, кроме рекурсии, обычно проблема XY.   -  person elclanrs    schedule 11.04.2015
comment
Честно говоря, в моем коде нет никаких проблем, но у меня есть функция с псевдонимом console.info, поэтому по сути c = console.info. Поэтому, когда я что-то утешаю с помощью указанной функции, в консоли просто отображается, что каждый раз это происходит из одного и того же места. я хотел вывести, какая функция вызвала это. Просто из-за моей лени и крутости в одном лице :D   -  person Jamie Hutber    schedule 11.04.2015
comment
Если это для отладки, devtools сделает все это за вас. Вы можете входить и выходить из вызовов функций, размещать операторы отладчика и так далее.   -  person elclanrs    schedule 11.04.2015
comment
да, конечно :) Но это означает нажатие f11.... Я не хочу делать что-то еще, если немного кода может сделать это за меня :p Я программист.. Это единственная причина, по которой я это делаю это... мне лень   -  person Jamie Hutber    schedule 11.04.2015
comment
Этот документ MDN дает объяснение почему он был удален из JS Strict Mode. По сути, возможность использовать arguments.callee и arguments.caller делала определенные оптимизации JS-движка трудными/невозможными.   -  person Phylogenesis    schedule 11.04.2015


Ответы (4)


Что бы это ни стоило, я согласен с комментариями выше. Для любой проблемы, которую вы пытаетесь решить, обычно есть лучшие решения.

Однако, просто для наглядности, вот одно (очень уродливое) решение:

'use strict'

function jamie (){
    var callerName;
    try { throw new Error(); }
    catch (e) { 
        var re = /(\w+)@|at (\w+) \(/g, st = e.stack, m;
        re.exec(st), m = re.exec(st);
        callerName = m[1] || m[2];
    }
    console.log(callerName);
};

function jiminyCricket (){
   jamie();
}

jiminyCricket(); // jiminyCricket

Я проверял это только в Chrome, Firefox и IE11, поэтому ваш результат может отличаться.

person p.s.w.g    schedule 11.04.2015
comment
ха отличная идея. Скиньте ошибку. Это действительно не имеет большого значения как таковое. Просто было бы неплохо узнать, откуда берутся файлы console.log. Я не вижу в этом проблемы? - person Jamie Hutber; 11.04.2015
comment
Это сработало хорошо. Нам пришлось использовать версию throw вместо решения @inetphantom, потому что встроенный движок JavaScript, с которым нам приходилось работать, не заполнял Error().stack до тех пор, пока он не был выброшен. - person RomSteady; 07.09.2016
comment
Привет, есть ли способ получить параметры вызывающей функции? - person easa; 03.08.2017
comment
@easa Я не думаю, что для этого будет общее решение. Вам действительно нужно проверить стек в отладчике. - person p.s.w.g; 04.08.2017
comment
@easa передает this функции, и у вас есть все, что вам нужно! - person inetphantom; 29.11.2018
comment
вы получили плюс, потому что уродство, но хитрость заставили меня смеяться - person Samer Murad; 27.05.2020
comment
Я не думаю, что вам нужно выдавать ошибку, достаточно просто запустить это регулярное выражение на new Error().stack - person Sandy Gifford; 30.06.2020

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

Краткая версия ответа @p.s.w.g (без выдачи ошибки, просто ее создание):

    let re = /([^(]+)@|at ([^(]+) \(/g;
    let aRegexResult = re.exec(new Error().stack);
    sCallerName = aRegexResult[1] || aRegexResult[2];

Полный фрагмент:

'use strict'

function jamie (){
    var sCallerName;
    {
        let re = /([^(]+)@|at ([^(]+) \(/g;
        let aRegexResult = re.exec(new Error().stack);
        sCallerName = aRegexResult[1] || aRegexResult[2];
    }
    console.log(sCallerName);
};

function jiminyCricket(){
   jamie();
};

jiminyCricket(); // jiminyCricket

person inetphantom    schedule 22.03.2016
comment
Регулярное выражение для соответствия имени в стеке, вероятно, должно быть ([^(]+) вместо (\w+), потому что пробелы и знаки препинания являются общими. - person maffews; 11.07.2017
comment
Вы добавили предупреждение для использования в продакшене... Хммм... Функция действительно не чистая. Но должно ли это быть серьезной причиной для того, чтобы не использовать его в рабочем коде? Код кажется довольно стабильным (насколько я могу судить). И очень интересное применение было бы в методе логирования. В этом случае передача имени вызывающего абонента в параметре была бы утомительной, раздутой и подверженной ошибкам. Итак, на мой взгляд, решение о том, почему и когда следует использовать определенный код в производстве или нет, в основном зависит от дизайна программного обеспечения и некоторого здравого смысла. Я с удовольствием буду использовать его в рабочем коде, если он мне подойдет. - person Bart Hofland; 28.08.2019
comment
Ах. Я вижу сейчас. Свойство Error.prototype.stack официально отмечено как нестандартные и специфичные для реализации. - person Bart Hofland; 28.08.2019
comment
Из документации Error.prototype.stack на MDN : Разные браузеры устанавливают это значение в разное время. Например, Firefox устанавливает его при создании объекта Error, в то время как PhantomJS устанавливает его только при выдаче Error, и архивные документы MSDN также, похоже, соответствуют реализации PhantomJS. Так что ответ pswg (включая создание, выдачу и отлов ошибки) в любом случае может быть более надежным... - person Bart Hofland; 28.08.2019
comment
@BartHofland Я бы все равно не стал его использовать. Где смысл регистрировать, кто вызвал функцию? Если есть ошибка - запишите эту ошибку. - person inetphantom; 28.08.2019
comment
Да, я согласен. Вы правы в этом. При обнаружении ошибки эта ошибка уже будет включать трассировку стека. Так что в этом случае мне не нужно было бы явно обращаться к трассировке стека. Вчера я исследовал эту проблему с трассировкой стека несколько глубже и пришел к выводу, что если мне нужно обрабатывать трассировку стека, я лично, скорее всего, буду использовать для этого специализированный сторонний пакет. Особенно, когда код будет развернут в (общедоступных) производственных средах. - person Bart Hofland; 30.08.2019

У меня это не сработало Вот что я наконец делаю, на всякий случай, если это кому-то поможет

function callerName() {
  try {
    throw new Error();
  }
  catch (e) {
    try {
      return e.stack.split('at ')[3].split(' ')[0];
    } catch (e) {
      return '';
    }
  }

}
function currentFunction(){
  let whoCallMe = callerName();
  console.log(whoCallMe);
}
person Benamar    schedule 05.06.2017
comment
Можете ли вы объяснить, почему это сработало для вас, а другие решения - нет? - person Noel Widmer; 05.06.2017
comment
У меня было что-то вроде исключения для индекса aRegexResult[1] вне допустимого диапазона - person Benamar; 06.06.2017
comment
aregexResult[1] выходит за пределы диапазона, потому что имена в стеке вызовов, которые не соответствуют \w+, пропускаются. Вместо этого вы должны использовать [^(]+. - person maffews; 11.07.2017
comment
Это решение должно работать намного быстрее, чем регулярное выражение. - person Sergey; 20.10.2018
comment
Кажется, это лучше всего работает для конфигурации Angular/TypeScript. - person Russ; 26.11.2020

Вы можете получить трассировку стека, используя:

console.trace()

но это, вероятно, бесполезно, если вам нужно что-то сделать с вызывающим абонентом.

См. https://developer.mozilla.org/en-US/docs/Web/API/Console/trace

person Larry    schedule 13.02.2019