Recently in the preparation of JS reverse hook class plug-in, and then need to obtain the current code execution location, convenient code positioning, so summarized below JavaScript how to output function call stack.

Demo code

 function main() {
   let a = fun('hello world')
   console.log(a)
 }
 ​
 function fun(a) {
   return a
 }
 ​
 main()
Copy the code

methods

console.trace()

Use the following

 function main() {
   let a = fun('hello world')
   console.log(a)
 }
 ​
 function fun(a) {
   console.trace('fun')
   return a
 }
 ​
 main()
Copy the code

The output is

Trace: fun at fun (c:\Users\zeyu\Desktop\demo\main.js:7:11) at main (c:\Users\zeyu\Desktop\demo\main.js:2:11) at Object.<anonymous> (c:\Users\zeyu\Desktop\demo\main.js:11:1) at Module._compile (node:internal/modules/cjs/loader:1095:14) at Object.Module._extensions.. js (node:internal/modules/cjs/loader:1124:10) at Module.load (node:internal/modules/cjs/loader:975:32) at Function.Module._load (node:internal/modules/cjs/loader:816:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12) at node:internal/main/run_main_module:17:47 hello worldCopy the code

Console.trace () can pass in arguments that will eventually be printed directly after trace, like fun here, but only in the console

IE6 doesn’t support it, but it’s probably not used anymore

arguments.callee.caller

In non-strict mode, you can print arguments directly, which prints the arguments called, and the function called, as follows

 function main() {
   let a = fun('hello world')
   console.log(a)
 }
 ​
 function fun(a) {
   console.log(fun.caller.toString())
   console.log(arguments)
   console.log(arguments.callee.toString())
   console.log(arguments.callee.caller.toString())
 ​
   return a
 }
 ​
 main()
Copy the code

The output is

 function main() {
   let a = fun('hello world')
   console.log(a)
 }
 [Arguments] { '0': 'hello world' }
 function fun(a) {
   console.log(fun.caller.toString())
   console.log(arguments)
   console.log(arguments.callee.toString())
   console.log(arguments.callee.caller.toString())
 ​
   return a
 }
 function main() {
   let a = fun('hello world')
   console.log(a)
 }
 hello world
Copy the code

Caller (fun.caller, arguments.callee.caller) print_function (toString); caller (fun.caller, arguments.callee.caller);

Caller is the upper function called by main. It is not difficult to find that each caller object has a caller attribute, namely the upper function of caller. As I am in node environment, I do not know what the caller is. ** Fun. caller and ‘arguments.callee.caller can print the upper function ** until caller is empty

[[FunctionLocation]] [FunctionLocation]] [FunctionLocation]] [FunctionLocation]]

To sum up:

Fun.caller == arguments.callee. Caller represents the execution environment of fun (upper function)

Arguments. callee stands for fun in progress

Premise: In non-strict mode

new Error().stack

As we all know, once the program fails, it will stop running directly and output an error message. The error message here includes the function called and the specific location. In contrast to the above method, this can be directly output in the execution environment, rather than simply displayed in the console.

The same code as above

 function main() {
   let a = fun('hello world')
   console.log(a)
 }
 ​
 function fun(a) {
   printStack()
   return a
 }
 ​
 function printStack() {
   let stack = (new Error()).stack
   console.log(stack)
 }
 ​
 main()
Copy the code

The output is a string, as follows

Error at printStack (c:\Users\zeyu\Desktop\demo\main.js:12:16) at fun (c:\Users\zeyu\Desktop\demo\main.js:7:3) at main (c:\Users\zeyu\Desktop\demo\main.js:2:11) at Object.<anonymous> (c:\Users\zeyu\Desktop\demo\main.js:16:1) at Module._compile (node:internal/modules/cjs/loader:1095:14) at Object.Module._extensions.. js (node:internal/modules/cjs/loader:1124:10) at Module.load (node:internal/modules/cjs/loader:975:32) at Function.Module._load (node:internal/modules/cjs/loader:816:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12) at node:internal/main/run_main_module:17:47 hello worldCopy the code

Because the result is a string, we can split the function (fun) and call location (c:\Users\zeyu\Desktop\demo\main.js:7:3)

 function main() {
   let a = fun('hello world')
   console.log(a)
 }
 ​
 function fun(a) {
   printStack()
   return a
 }
 ​
 main()
 ​
 function printStack() {
   const callstack = new Error().stack.split("\n");
   callstack.forEach((s) = > {
     let matchArray = s.match(/at (.+?) ((. +?) ) /)
     if(! matchArray)return
 ​
     let name = matchArray[1]
     let location = matchArray[2]
     console.log(name, location)
   })
 }
Copy the code

The output is as follows (since this is a Node environment, it will output something about modules)

printStack c:\Users\zeyu\Desktop\demo\main.js:14:21 fun c:\Users\zeyu\Desktop\demo\main.js:7:3 main c:\Users\zeyu\Desktop\demo\main.js:2:11 Object.<anonymous> c:\Users\zeyu\Desktop\demo\main.js:11:1 Module._compile node:internal/modules/cjs/loader:1095:14 Object.Module._extensions.. js node:internal/modules/cjs/loader:1124:10 Module.load node:internal/modules/cjs/loader:975:32 Function.Module._load node:internal/modules/cjs/loader:816:12 Function.executeUserEntryPoint [as runMain] node:internal/modules/run_main:79:12  hello worldCopy the code

conclusion

Console.trace () is the best option if you want to output the call stack during debugging, but it can only be displayed on the console, not used in the runtime environment

Arguments.callee. caller uses the premise of non-strict mode, so delete “use strict”; Code, but can directly print out the complete function, and call the parameters passed.

New Error().stack is equivalent to actively reporting an Error. Since an Error will automatically print the call information where the Error is reported, the function name, line and column of the code can be accurately located, and the location of the code to be located is preferred.