DEV Community

Vishal Singh
Vishal Singh

Posted on

Demystifying JavaScript: Execution Contexts, Hoisting, Scopes & Closures

What Are Execution Contexts?

Execution Contexts manage code complexity for the JavaScript engine, similar to how functions manage authoring complexity. The engine creates them in two types: Global Execution Context at startup and Function Execution Contexts on function invocation.
Each context has a Creation phase and an Execution phase. In Creation, the engine sets up the global object (window in browsers, global in Node), this, memory for variables/functions, initializes variables to undefined, and loads function declarations fully. [

Hoisting Explained

Hoisting occurs during Creation when variable declarations get undefined and functions get fully loaded, before line-by-line execution. This explains why console.log(name) before var name = 'Tyler'; outputs undefined—no physical movement happens.

console.log('name: ', name);  // undefined
console.log('getUser: ', getUser);  // [Function: getUser]
var name = 'Tyler';
function getUser() {
  return { name: name };
}
Enter fullscreen mode Exit fullscreen mode

Function declarations hoist completely, unlike variables.

Function Execution Contexts

Function Contexts create an arguments object instead of a global object, plus this, and hoist locals. Invocations push new contexts onto the Call Stack; completion pops them off, as JavaScript is single-threaded.

Arguments become local variables, and inner variables stay in their context. For example, passing handle to getURL(handle) adds it locally alongside globals.

Scopes and Scope Chain

Scope defines variable accessibility as the current Execution Context. Locals can't access outer variables post-pop, causing ReferenceError for console.log(bar) after foo() where bar is local to foo.

If absent locally, the engine climbs the Scope Chain to parents up to Global. Multiple name variables in different contexts resolve locally first: outputs undefined, Jordyn, Jake, Tyler.

Closures in Action

Closures let inner functions access outer scopes post-parent execution via a persistent Closure Scope. In makeAdder(x), the returned inner retains x despite makeAdder's context popping.

function makeAdder(x) {
  return function inner(y) {
    return x + y;
  };
}
const add5 = makeAdder(5);
console.log(add5(2));  // 7
Enter fullscreen mode Exit fullscreen mode

for More infomation visit to

https://fireship.dev/ultimate-guide-to-execution-contexts-hoisting-scopes-and-closures-in-javascript

Top comments (0)