Documentation

Move Nested Function

Reference guides for release workflows, command-line usage, cross-file protections, and the desktop app.

Inside the Docs

Practical guides for real release work.

How-to guides Start with release sequencing and command-line usage, then move into feature-specific references.
Advanced protection Browse cross-file controls like Replace Globals and Protect Members when a build spans multiple scripts.

Move Nested Function

  • MoveNested
  • Enterprise

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.

Frequently asked questions

What does moving a nested function actually take away from a reader?

Free labelling. An anonymous function sitting inside a registration call is documented by the call that registers it: a reader who sees a submit handler being attached knows what the body immediately following it does, without understanding any of your code. The same is true of an object literal full of inline handlers, where the keys describe each function. Once the bodies are elsewhere, the call site says only that a function goes here, and finding out which one means following a generated identifier.

Does relocating functions change how my code behaves?

No. The transform preserves behaviour, and where it could not, it does not move the function. What changes is the visual adjacency between a callback and the thing that registers it, not the semantics of either. Anything that depends on where a function was written rather than on what it does is the exception, which is why the transform is conservative about closures and arrow functions.

Why did some of my functions stay where they were?

Because moving them would have changed what they can see, and that constraint is deliberate. A function that closes over a local or a loop variable is pinned by the declaration it depends on, and hoisting it above that declaration would change its captured values. Arrow functions take their surrounding binding lexically, which makes their position meaningful and limits how far they can travel. Functions left in place are the transform declining to break your code, not the transform failing.

Does this affect what I see in a stack trace?

Yes, and it is worth planning for before you need it. A relocated function reports the position it now occupies rather than the one you wrote, so a trace from production points somewhere that does not correspond to your source layout. Keep the identifier map for the release and demangle traces against it rather than reading them raw. That workflow is the same one every structural transform requires.

Which option should I pair it with?

Flat transform, if you want the effect to compound. Relocation removes the meaning carried by a function's position; rewriting the surrounding control flow into dispatch removes the meaning carried by statement order. Applied together, source position tells a reader almost nothing about execution order, which is a substantially stronger result than either produces alone. See <a href="FlatTransform.aspx">flat transform</a>.

Is there a runtime cost?

It is small and structural rather than per-call: the functions still exist, still get called the same number of times, and are simply declared elsewhere. The cost worth watching is on debugging rather than on execution, because the output no longer reads in the order you wrote it. That is the trade the option exists to make, so enable it where the code is worth protecting and leave it off where readability during an incident matters more.

Try this in the online obfuscator

Paste your own code and see this option applied, or compare plans for larger projects and the desktop app.

Try It Free See Pricing