JS output function call stack

Recently, I was writing a JS reverse hook plug-in, and then I need to get the location of the current code execution to ...
Demo code
method
summary

Recently, I was writing a JS reverse hook plug-in, and then I need to get the location of the current code execution to facilitate code positioning, so I'll summarize   JavaScript   How to output the function call stack.

Demo code

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

method

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 code

The output result 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 world Copy code

console.trace() can pass in parameters, which will be directly output after trace, such as fun here, but can only be output in the console

But IE6 doesn't support it, but no one should use it

arguments.callee.caller

In the non strict mode, you can directly output arguments, and then print the called parameters and the called function, 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 code

The output result 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 code

We have successfully printed out the currently running functions (toString is used here to print out the functions), and the superior functions can be obtained through fun.caller and arguments.callee.caller.

Caller is the upper level function called, that is, the main function here. It is not difficult to find that there is a caller attribute under each caller object, that is, the upper level function of caller. Because I have a node environment here, I don't know what the caller of caller here is... Anyway, this is not the focus of attention. The focus is that * * fun.caller and ` arguments.callee.caller can print the upper function * * until the caller is empty

The [[FunctionLocation]] in the other outer ring is the location of the function. Unfortunately, this is not a caller attribute and is only used by the js engine, so it cannot be output.

To sum up:

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

arguments.callee represents the fun being executed

Premise: in non strict mode

new Error().stack

As we all know, once the program makes an error, it will directly stop running and output error information. The error information here includes the called function and specific location. Compared with the above methods, this can be directly output in the execution environment rather than simply displayed on 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 code

The output result 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 world Copy code

Since the result is a string, you can get the function (fun) and the calling location (c:\Users\zeyu\Desktop\demo\main.js:7:3) by splitting it by split, as shown below

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 code

The output results are as follows (because it is a Node environment, some modules will be output)

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 world Copy code

summary

If you want to output the call stack as a debugging phase, console.trace() is certainly the best choice, but it can only be displayed on the console and cannot be used in the running environment

The premise of using arguments.callee.caller is in non strict mode, so if you want to use it, you need to delete "use strict"; Code, but it can directly print out the complete function and the parameters passed in by the call.

new Error().stack   It is equivalent to active error reporting. Since the error reporting will automatically print the call information where the error is reported, it can accurately locate the function name, code lines and columns of the code, and it is preferred for the subsequent location of the code.

14 October 2021, 21:13 | Views: 9957

Add new comment

For adding a comment, please log in
or create account

0 comments