Reputation: 844
Is it possible to find out where a function is called from? If yes, then how to detect, if a function is called from a global scope, from another function, or perhaps from a browser console?
Take a look at the following example:
<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>
I know that this line callerName = arguments.callee.caller.name;
in the example above, would give me caller function's name. But I don't know how to detect if a function was called from a global scope. For instance if I change myFunc2()
and add an if else
statement to check if arguments.callee.caller.name
returns an undefined
value, knowing that this will happen, when a function is called from a global scope:
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');
}
}
However, this will not work if myFunc2()
is called from a global scope and callerName = arguments.callee.caller.name;
will cause JavaScript to throw the following error:
TypeError: 'null' is not an object (evaluating 'arguments.callee.caller.name')
So I am back to square one, and the question still remains:
Upvotes: 31
Views: 24409
Reputation: 11
You might just create an instance of Error & call its stack method inside the function to see the call stack
const stack = new Error().stack()
console.log(stack)
above two lines of code should be inside the function body, an example might be
function calculateAge() {
const stack = new Error().stack();
console.log(stack);
}
Upvotes: 0
Reputation: 6044
In Chrome, you can use:
console.trace();
Just add that line in your function, I usually place it as the first line. If you view the console you'll see the name of your function, and below that line you'll see where it's being called from.
Upvotes: 40
Reputation: 844
In JavaScript most things are objects, when you declare callerName = new String
you create a string object with some properties and methods. For instance, the valueOf()
method will return the primitive value of a string object. However, just like JavaScript tells you 'TypeError: 'null' is not an object
null is not an object but rather, it's the absence of an object. null doesn't have any methods or properties. When a function is called from a global scope, arguments.callee.caller
evaluates caller to null. Soarguments.callee.caller.name
is like trying to access null's name
property (null.name
), but null doesn't have a property called name
, since it's not an object and can not have any property at all. This is why JavaScript complains, because you are trying to access something that doesn't exist. What you can do however, is to first check if caller
is a falsy value by using a simple if else
statement if(!arguments.callee.caller)
, if it isn't, then you can access the name
property of the caller
and find out what function has called myFunc2()
, but if it is, then you know the function was called from a global scope.
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');
}
}
Upvotes: 2
Reputation: 2036
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
func2 is called it will display its caller name, if it was called within another function scope, it will display that function's name and if it was called from global scope it will display a message that shows it was called from the global scope.
Upvotes: 3
Reputation: 6266
That's quite a tricky question. As discussed on this answer Arguments.callee is deprecated in some browsers.
Depending on your approach you can use Function.caller. I have written a quite simple example
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();
Another more generic example can be found here
Still 'use strict'
makes both these approaches fail, so using a try / catch
block can solve your problem or you may simulate a "dummy call stack" for your functions ( depending on the fact that all your code works synchronously )
Upvotes: 1
Reputation: 16033
Depending on your browser, you could provoke and error, by accessing an undefined variable for example, inside a try/catch
. Then examine the stack trace some browsers provide in the error.
This will be very browser specific.
Upvotes: 4
Reputation: 71908
If the function is called from the global scope, arguments.callee.caller.name
will be undefined. Otherwise, it will be the name of the caller function (which also represents the scope it was called from).
So what you already have should work, except in strict mode, where arguments.callee
is not available.
Additionaly: the developer tools available from your browser are probably a better way to inspect this kind of thing: just set a breakpoint and look at the stack trace panel. Unless of course your code itself needs to know the calling scope at runtime.
Upvotes: 8