Suggest an editImprove this articleRefine the answer for “What is execution context?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Execution context** - the internal environment the JavaScript engine creates for every piece of code it runs, holding that code's variables, scope chain, and `this` binding. ```javascript var x = 1; function show() { var y = 2; console.log(x); // 1 - found via scope chain to global context console.log(y); // 2 - local to this function's context } show(); ``` **Key:** each function call gets its own context. Contexts stack up on the call stack during execution and pop off when the function returns.Shown above the full answer for quick recall.Answer (EN)Image**Execution context** - the internal environment the JavaScript engine creates every time it runs code, holding that code's variables, scope chain, and `this` binding. ## Theory ### TL;DR - Think of it as a chef's workstation: each function call gets its own workspace with ingredients (variables), a reference book (scope chain), and a name tag for who owns it (`this`). - Three types: global (one per program), function (one per call), eval (avoid it). - Two phases: creation (hoisting happens here) and execution (code runs line by line). - `this` changes per context. Arrow functions skip creating their own and inherit from the parent. - When you hit an unexpected `undefined` or wrong `this`, trace the context stack. ### Quick example ```javascript console.log(a); // undefined - hoisted in global context's creation phase var a = 2; console.log(a); // 2 function greet() { // New function context pushed onto the call stack console.log(b); // undefined - hoisted within this context only var b = 'hello'; console.log(b); // 'hello' } greet(); ``` Global context hoists `a` to `undefined` during creation. When `greet()` runs, a fresh function context is pushed onto the call stack with its own `b`. That context can reach `a` via the scope chain, but `b` lives only inside it. ### Two phases every context goes through The engine runs each context in two steps. **Creation phase**: `var` declarations are hoisted and set to `undefined`. Full function declarations are hoisted as-is. The scope chain is built. `this` is resolved. **Execution phase**: code runs line by line, values are assigned, functions are called. This is why reading `x` before `var x = 1` gives `undefined` instead of a ReferenceError. The variable was registered during creation, just without a value yet. ### How execution context differs from scope [Scope](/questions/what-is-scope) describes what variables a piece of code can see. Execution context is the full package: the variable object (all `var` declarations and function declarations), the scope chain pointing outward to parent contexts, the `this` value, and the position on the call stack. Scope is one component of context, not the whole thing. ### `this` across contexts In a method call, `this` is the object before the dot. In a standalone function call, `this` is the global object (or `undefined` in strict mode). Arrow functions do not create their own context. They capture `this` from the enclosing context at definition time. ```javascript const obj = { name: 'World', hello: function() { console.log(this.name); // 'World' - method context, this = obj setTimeout(function() { console.log(this.name); // undefined - new global context }, 0); setTimeout(() => { console.log(this.name); // 'World' - arrow inherits this from hello }, 0); } }; obj.hello(); ``` The regular function in `setTimeout` gets its own global context. The arrow function does not create one at all. ### Common mistakes **1. Expecting `var` to be block-scoped** ```javascript if (true) { var score = 100; } console.log(score); // 100 - var belongs to the function or global context ``` `var` is scoped to its execution context, not to `{}` blocks. Use `let` or `const` for block scoping via LexicalEnvironment. **2. Losing `this` in callbacks** ```javascript class Timer { constructor() { this.count = 0; } start() { setInterval(function() { this.count++; // TypeError: this is undefined in strict mode }, 1000); } } ``` This is probably the most common `this` question in junior JavaScript interviews. The callback runs in a new context where `this` is not the Timer instance. Fix: use an arrow function in the callback, or bind `this` in the constructor. **3. Expecting `eval` to be isolated** ```javascript var secret = 'admin'; eval('console.log(secret)'); // 'admin' - shares the calling context's scope ``` `eval` creates its own context but inherits the outer scope. It also blocks several V8 optimizations. Use `new Function()` if you need dynamic code in a genuinely isolated context. **4. Forgetting strict mode changes `this`** In non-strict mode, `this` in a standalone function call is the global object. In strict mode, it is `undefined`. Adding `"use strict"` to an existing file can silently break code that depended on `this === window`. ### Real-world usage - **React function components**: each render creates a new function context. [Hooks like `useState`](/questions/what-is-usestate) capture state for that context via closures. - **Express route handlers**: each request runs in its own function context. `req` and `res` are local to that call. - **`setTimeout` callbacks**: they run in a new global context. Arrow functions are the standard fix for preserving the outer `this`. - **Node.js modules**: each file runs inside a wrapper function, so top-level `var` does not leak to the global object. ### Follow-up questions **Q:** What is the difference between the creation phase and the execution phase? **A:** Creation phase hoists `var` declarations to `undefined`, hoists function declarations in full, and resolves `this`. Execution phase runs the code line by line and assigns values. **Q:** How does the scope chain work across contexts? **A:** Each context holds a reference to its outer context's variable environment. When a variable is not found locally, the engine walks up the chain until it reaches the global context. **Q:** What is the difference between the call stack and the execution context stack? **A:** They describe the same structure from two angles. The call stack tracks which functions are waiting to return. The execution context stack holds the full state of each frame: variables, scope chain, and `this`. **Q:** How do [arrow functions](/questions/arrow-functions-vs-regular-functions) affect execution context? **A:** Arrow functions do not create their own context. They inherit `this` and scope from the lexical parent at the time of definition. **Q:** Why is `this` `undefined` in Node.js strict mode inside a function? **A:** Strict mode does not assign the global object to `this` in standalone function calls. The value stays `undefined` until explicitly set via `.call()`, `.apply()`, or `.bind()`. ## Examples ### Hoisting across global and function contexts ```javascript // Global context - 'name' hoisted to undefined in creation phase console.log(name); // undefined var name = 'Alice'; console.log(name); // 'Alice' function getGreeting() { // Function context - runs its own creation phase console.log(greeting); // undefined (hoisted inside this context) var greeting = 'Hello, ' + name; // 'name' found via scope chain console.log(greeting); // 'Hello, Alice' } getGreeting(); ``` `name` is reachable inside `getGreeting` through the scope chain pointing to the global context. `greeting` is local to the function's context and does not exist outside it. ### `this` binding in a React component ```javascript function UserProfile({ userId }) { // New execution context on every render const [user, setUser] = React.useState(null); React.useEffect(() => { // Arrow function - no own context, inherits from UserProfile fetch(`/api/user/${userId}`) // userId from this render's context .then(res => res.json()) .then(setUser); }, [userId]); return user ? <div>{user.name}</div> : <div>Loading...</div>; } ``` Each render of `UserProfile` creates a fresh execution context. The arrow function in `useEffect` closes over `userId` from that specific render. Leave `userId` out of the dependency array and the effect will hold onto a stale value from an old context.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.