Move Nested Function lifts nested and anonymous function expressions out of their original position and leaves a reference behind. The behavior is unchanged; what is lost is the visual adjacency between a callback and the thing that registers it.
Example
Before:
a.onclick(function () {});
b = { onclick: function () {} };
After the function references are separated:
a.onclick(c);
b = { onclick: d };
Why it helps
Anonymous functions leak intent through position. A reader who finds addEventListener("submit", ...) does not need to understand your code to know that the body immediately following it is your form-submit logic — the registration names the behavior for them. The same is true of an object literal full of inline handlers: the keys document what each function is for.
Once the bodies are elsewhere, that free labelling is gone. The call site says a function goes here; finding out which function means following a generated identifier. Multiply that across a bundle with hundreds of callbacks and the reader has lost their fastest orientation technique.
It pairs particularly well with Flat Transform: once bodies have been relocated and the surrounding control flow has been rewritten into dispatch, source position carries almost no information about execution order.
Configuration
The engine option and its config alias:
{
"moveNestedFunction": true
}
{
"options": {
"MoveNested": true
}
}
moveNestedFunction is a convenience alias for options.MoveNested — set either one, not both.
Closures and this are the thing to watch
Relocating a function is only safe when the destination scope can still see everything the body referenced. That constrains what the transform will move, and it is why some functions in your file will be left where they are:
- Captured variables pin a function in place. A callback that closes over a loop variable or a local cannot be hoisted above the declaration it depends on without changing what it sees.
this binding is determined by the call, not the definition — so for ordinary function expressions relocation does not change this. Arrow functions capture this lexically, which makes their position meaningful and limits how far they can move.
- Named function expressions can refer to themselves by name inside their own body; that self-reference has to survive the move.
- Methods relying on implicit receivers are the classic breakage shape across obfuscators generally. Test object-literal-heavy and class-heavy code specifically.
Run your test suite against protected output rather than reasoning about which of these apply to you. This is an Enterprise-tier structural transform and it deserves the same care as Deep Obfuscation: enable it alone, confirm green, then layer.
Effect on stack traces
Relocated anonymous functions get generated names, so production traces name those instead of pointing at a line inside the function that registered them. That is a debugging cost, not a correctness one, and it is what symbolication exists to reverse — keep the identifier map from each protected build and demangle traces on the way in. The workflow is in debug obfuscated JavaScript in production.
Best pair: enable this together with the stronger structure options —
Flat Transform and
Code Transposition — when you want the final code to look much less like the original source layout. On its own it changes the shape of callbacks; combined, it changes the shape of the program.