Как узнать, откуда вызывается функция в JavaScript?

Можно ли узнать, откуда вызывается функция? Если да, то как определить, если функция вызывается из глобальной области, из другой функции или, возможно, из консоли браузера?

Взгляните на следующий пример:

<script>
    function myFunc1() {
        // some code
        myFunc2(); // I was called from myFunc1()
    }
    function myFunc2() {
        var callerName = new String;
        callerName = arguments.callee.caller.name;
        // some code
        alert('I was called from ' + callerName + ' function');
    }
    myFunc2(); // I was called from global scope
</script>

Я знаю, что эта строка callerName = arguments.callee.caller.name; в приведенном выше примере дала бы мне имя функции звонящего. Но я не знаю, как определить, вызвана ли функция из глобальной области. Например, если я изменяю myFunc2() и добавляю оператор if else, чтобы проверить, возвращает ли arguments.callee.caller.name значение undefined, зная, что это произойдет, когда функция вызывается из глобальной области:

myFunc2() {
var callerName = new String;
callerName = arguments.callee.caller.name;
    if(callerName == undefined) {
        alert('I was called from global scope');
    } else {
        alert('I was called from ' + callerName + ' function');
    }
}

Однако это не сработает, если вызов myFunc2() вызывается из глобальной области, а callerName = arguments.callee.caller.name; приведет к тому, что JavaScript выведет следующую ошибку:

TypeError: 'null' is not an object (evaluating 'arguments.callee.caller.name')

Итак, я вернулся к квадрату, и вопрос все еще остается:

  • Как определить, вызвана ли функция из глобальной области?
  • Если он вызван из глобальной области, это из консоли браузера?

Ответы

Ответ 1

Если функция вызывается из глобальной области видимости, arguments.callee.caller.name будет undefined. В противном случае это будет имя функции вызывающего абонента (которая также представляет область действия, из которой она была вызвана).

Итак, у вас уже есть работа, кроме строгий режим, где arguments.callee недоступен.


Дополнительно: инструменты разработчика, доступные в вашем браузере, вероятно, лучший способ проверить такие вещи: просто установите точку останова и посмотрите на панель трассировки стека. Если, конечно, сам код не должен знать область вызова во время выполнения.

Ответ 2

В Chrome вы можете использовать:

console.trace();

В вашей функции просто добавьте эту строку, я обычно помещаю ее как первую строку в моей функции. Если вы просмотрите консоль, вы увидите имя своей функции, а ниже этой строки вы увидите, откуда она вызывается.

Ответ 3

В зависимости от вашего браузера вы можете спровоцировать и выполнить ошибку, обратившись к переменной undefined, например, внутри try/catch. Затем просмотрите трассировку стека, которую некоторые браузеры предоставляют в ошибке.

Это будет очень специфичным для браузера.

Ответ 4

function func1() {
    // some code
    func2(); // I was called from func1()
}
function func2() {
var callerName = new String;
callerName = arguments.callee.caller ? arguments.callee.caller.name : "global";
    if(callerName == "global") {
        alert('I was called from global scope');
    } else {
        alert('I was called from ' + callerName + ' function');
    }
}
func1();
func2(); // I was called from global scope

Ответ 5

В JavaScript большинство вещей являются объектами, когда вы объявляете callerName = new String, вы создаете строковый объект с некоторыми свойствами и методами. Например, метод valueOf() возвращает примитивное значение строкового объекта. Однако, как и JavaScript, вы указываете 'TypeError: 'null' is not an object null не объект, а скорее отсутствие объекта. null не имеет никаких методов или свойств. Когда функция вызывается из глобальной области видимости, arguments.callee.caller оценивает вызывающего абонента на null. Так что arguments.callee.caller.name похоже на попытку access null name свойство (null.name), но null не имеет свойства, называемого name, поскольку оно не является объектом и не может иметь никакого свойства. Вот почему JavaScript жалуется, потому что вы пытаетесь получить доступ к тому, что не существует. Однако вы можете сначала проверить, является ли значение caller ложным значением с помощью простого оператора if else if(!arguments.callee.caller), если это не так, вы можете получить доступ к свойству name caller и узнать, какая функция вызвала myFunc2(), но если это так, то вы знаете, что функция вызывается из глобальной области.

function myFunc2() {
    if(!arguments.callee.caller) {
        callerName = "global";
        alert('I was called from global scope');
    } else {
        callerName = arguments.callee.caller.name;
        alert('I was called from ' + callerName + ' function');
    }
}

Ответ 6

Это довольно сложный вопрос. Как обсуждалось в этом ответе, Arguments.callee устарел в некоторых браузерах.

В зависимости от вашего подхода вы можете использовать Function.caller. Я написал довольно простой простой пример

function A() {
    if (A.caller === null || A.caller.name == "") console.log("Function called from top window")
    else console.log("Called from " + A.caller.name);
    B();
}

function B() {
    if (B.caller === null || B.caller.name == "") console.log("Function called from top window")
    else console.log("Called from " + B.caller.name);
}

A();

Еще один общий пример можно найти здесь

Тем не менее 'use strict' приводит к сбою обоих этих подходов, поэтому использование блока try / catch может решить вашу проблему или вы можете имитировать " фиктивный стек вызовов" для ваших функций (в зависимости от того, что весь ваш код работает синхронно)