Как узнать, откуда вызывается функция в 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
может решить вашу проблему или вы можете имитировать " фиктивный стек вызовов" для ваших функций (в зависимости от того, что весь ваш код работает синхронно)