JavaScript runtime guide

How JavaScript Executes Code: From Global Code to Function Return

A precise mental model for JavaScript execution contexts, function calls, lexical environments, and the call stack.

JavaScript evaluates executable code inside an execution context. Global code starts in one context; each ordinary function call creates another context in which that function body runs.

This is a practical guide to the model used by the Deep JS visualizer. It uses specification terms where they help, while keeping the focus on a trace you can inspect rather than on engine implementation details.

The short answer

  • Global code and function bodies run in execution contexts.
  • Calling a function adds its work above the caller on the call stack; returning resumes the caller.
  • When code reads a name, JavaScript resolves it through lexically nested environments, not by where the function happened to be called.

1. Begin with executable code and an execution context

Before a script or function body is evaluated, the engine prepares the execution context that will be active while that code runs. The context has links to the lexical environments used for identifier resolution and a this binding appropriate to the code being evaluated.

The global execution context is active while top-level script code runs. A function execution context becomes active only when that function is called. The visualizer represents these active contexts as stack frames so that the order of work is visible.

2. Preparation and evaluation are different moments

A declaration can be made available while its surrounding code is being prepared, before the statement that appears at its source position is evaluated. That distinction explains why a function declaration may be callable earlier in its scope.

It does not mean that every value is magically assigned at the top of a file. var bindings, lexical declarations, function declarations, and class declarations have different initialization rules.

A function declaration is initialized before this call is evaluated

sayHello("Ada");

function sayHello(name) {
  console.log(`Hello, ${name}`);
}

3. A function call creates nested work

When evaluate reaches a call expression, the caller pauses while the callee runs. The function call creates a function execution context, initializes its parameters and local bindings according to the language rules, and places that work above the caller.

After the function completes, its context is removed from the active call stack and evaluation continues at the next operation in the caller. The stack is therefore a record of active work, not a list of every function that exists.

The call to format runs before the outer console.log completes

function format(name) {
  return `Hello, ${name}`;
}

console.log(format("Ada"));

4. Identifier lookup follows lexical structure

Inside speak, the name greeting is not a local binding. JavaScript checks the environment for speak and then follows its outer-environment link to the environment in which speak was created. There it finds greeting.

That outer link comes from the function’s lexical creation site. Moving the call expression to a different caller does not change where greeting is resolved.

greeting is found in the outer lexical environment

const greeting = "Hello";

function speak(name) {
  console.log(`${greeting}, ${name}`);
}

speak("Ada");

5. What the visualizer models

Deep JS focuses on the parts of a trace that make synchronous code understandable: active stack frames, bindings, outer environments, function calls, returns, and console output. It is an educational model, not a claim to expose a browser engine’s private memory layout.

Use the trace to form a prediction first: which context is active, where will a name be found, and what returns next? Then step through the visualizer and compare that prediction with the model.

Try it yourselfRun this model in Deep JSEdit a program, step through it, and inspect the active call stack, execution context, environment links, and console output.