JavaScript Core Concepts - Deep Dive
Wednesday, January 14, 2026
•By Kanad Shee - Full Stack Developer
Master JavaScript fundamentals with in-depth explanations of most of the core concepts

Deep Dive into JavaScript
A comprehensive guide to mastering JavaScript fundamentals from execution context and closures to async patterns and the this keyword.
Understanding JavaScript at a deep level is what separates developers who merely use the language from those who truly master it. While it's easy to write functional JavaScript code, grasping the underlying mechanics—how the engine executes code, manages memory, and handles asynchronous operations—unlocks a new level of problem-solving ability and code quality.
In this comprehensive guide, I've compiled everything you need to understand JavaScript's core concepts that form the foundation of modern web development. From the often-misunderstood hoisting mechanism to the powerful patterns enabled by closures, from the event loop's asynchronous nature to the nuanced behavior of the this keyword—these are the concepts that appear in every interview, every code review, and every production application.
What makes JavaScript truly fascinating is how its execution model differs from traditional programming languages. Understanding concepts like the call stack, lexical environment, and scope chaining isn't just academic knowledge—it's what helps you debug complex issues, optimize performance, and write predictable code. The temporal dead zone, block scope, and closure patterns are not just interview questions; they're the mechanisms that power modern JavaScript frameworks and libraries.
This guide takes you through practical examples and real-world scenarios that demonstrate each concept in action. You'll learn how promises and async/await revolutionized asynchronous programming, how higher-order functions enable functional programming patterns, and how map, filter, and reduce make array transformations elegant and declarative.
Whether you're preparing for technical interviews, debugging production issues, or simply want to write better JavaScript code, this deep dive covers the essential concepts that every JavaScript developer must master. Each section includes working code examples, common pitfalls, and best practices derived from real-world experience.
Introduction
This guide walks you through JavaScript's fundamental concepts that power modern web development:
- Hoisting & Execution Context - How JavaScript processes code before running it
- Scope, Lexical Environment & Scope Chaining - Variable accessibility and closure mechanisms
- let, const & Temporal Dead Zone - Modern variable declarations and their behavior
- Block Scope & Shadowing - How blocks create new scopes and variables interact
- Closures - Functions bundled with their lexical environment
- Event Loop & Asynchronous JavaScript - How JavaScript handles non-blocking operations
- Callbacks, Promises & Async/Await - Evolution of asynchronous patterns
- Higher Order Functions - Functions that operate on other functions
- Map, Filter & Reduce - Functional array transformation methods
- The this Keyword - Context binding in different scenarios
Hoisting
Hoisting is a behavior where variable and function declarations are conceptually moved to the top of their current scope during the compilation phase, before the code is executed. This allows accessing variables and methods before they are initialized in the code.
Functions and Execution Context
A function in JavaScript is a reusable block of code that performs a specific task or calculates a value. Functions are fundamental building blocks that help organize code, make it modular, and avoid repeating logic.
Window and This Keyword
If we don't write anything in code, a global object will still be created along with the Global Execution Context. In browsers, this is the window object. Anything written at the top level (not inside any functions) will be attached to this window object.
Undefined vs Not Defined
Undefined
Undefined is a special keyword assigned to a variable until a value has been initialized. JavaScript allocates memory for that variable in the Memory Allocation Phase.
Not Defined
This means accessing a variable or function which doesn't exist in the code. The JS engine will not allocate any memory for it and will show an error.
Scope and Lexical Environment
Scope
Scope defines where we can access specific variables and functions in our code.
Lexical Environment
Lexical Environment is the local memory and the lexical environment of its parent.
Scope Chaining
The way of finding the value for a variable in local memory along with its parent lexical environment is known as Scope Chaining.

let, const and Temporal Dead Zone
let
Using let, when we declare any variable, it allocates memory but not in the global object. It's stored in a separate memory space, and we can't access that value before it has been initialized.
const
In case of const, everything is similar to let, but we must initialize it with a value immediately.
Block Scope and Shadowing
Block
A block is used to combine multiple statements in a group. It is also known as a compound statement.
Block Scope
All the variables and functions we can access inside a block is known as block scope.
Shadowing
Illegal Shadowing
Shadowing occurs when an inner variable has the same name as an outer variable. It becomes illegal when a var declaration tries to redeclare a variable that was already declared with let/const in the same scope.
Closure
Functions along with its lexical environment forms a closure.
When we return a function, it doesn't just return the function—it comes as a bundle along with its lexical scope as a closure. This is why values remain accessible.
Nested Closures
setTimeout with Closures
JavaScript does not wait for setTimeout. All 5 callbacks form closures over the same i variable, so they all see the final value of i which is 6.
Solution using let
Solution using Helper Function
First Class Functions
Anonymous Function
A function without a name is an anonymous function.
Function Statement
Function Expression
Named Function Expression
Parameters vs Arguments
num1 and num2 are parameters. 10 and 20 are arguments.
Arrow Functions
Introduced in ES6, arrow functions provide a concise syntax and have lexical this binding.
Callback Functions
Functions are first class citizens in JavaScript. We can pass one function into another function. The function passed as an argument is known as a callback function.
Event Listeners with Closures
Memory Management
Closures keep their scope with them, so values remain attached. It's a good practice to remove event listeners to prevent memory leaks.
Event Loop and Asynchronous JavaScript
Promises and Mutation Observer go to the Microtask Queue. Web APIs callback functions go to the Callback Queue.
When all tasks from the Microtask Queue are completed, only then the Callback Queue's tasks will be executed.
Starvation
When there are many tasks in the microtask queue and few in the callback queue, the callback queue has to wait. This waiting period is known as Starvation Time of Callback Queue.
setTimeout Trust Issues
JavaScript uses a Concurrency Model where the call stack, event loop, and callback queue decide how code executes.
Higher Order Functions
Functions which take other functions as arguments or return a function are known as Higher Order Functions.
Calculate Example
Custom Map Polyfill
Map, Filter, and Reduce
map()
Map takes an array and performs an operation on each item, returning a transformed array.
filter()
Filter is a higher order function which filters values according to a condition and returns the filtered result.
reduce()
Reduce runs a callback function on each element of the array, passing the return value from the calculation on the preceding element. The final result is a single value.
Practical Examples
Callback Problems
Callback Hell
Deeply nested callbacks make code hard to read and maintain.
Inversion of Control
Inner callback functions are directly dependent on the outer function, which means we're trusting that function blindly.
Promises
A Promise in JavaScript is an object that represents the eventual completion or failure of an asynchronous operation.
Promise States
- Pending: The initial state, neither fulfilled nor rejected
- Fulfilled: The operation completed successfully
- Rejected: The operation failed
Promise Chaining
Promise chaining executes multiple asynchronous operations in sequence, where the output of one .then() is passed as input to the next.
Promise Example
Async and Await
async
The async keyword creates async functions. It always returns a promise. If we return a value, it will automatically wrap that value inside a promise.
await
The await keyword can only be used inside an async function. It pauses the execution of the async function until the Promise is resolved or rejected.
async/await Execution
When the JS engine encounters an await, it pauses execution of that function, schedules the rest to be resumed later, and the call stack is freed up to execute other code.
Fetching Data
Error Handling
Promise APIs
Promise.all
Executes multiple promises in parallel. Returns results in the same order as the input array. Takes the time of the slowest promise. If any promise rejects, it immediately rejects without waiting for others.
Promise.allSettled
Similar to Promise.all but waits for all promises to settle regardless of success or failure. Returns an array of objects with { status, value/reason }.
Promise.race
All promises start executing simultaneously. The first one to settle (resolve or reject) decides the result.
Promise.any
Similar to Promise.race but only cares about the first fulfilled promise. Ignores rejections until all promises reject. If all promises reject, returns an AggregateError.
The this Keyword
this in Global Space
In the global execution context, this refers to the global object. In browsers, this is the window object.
this Inside a Function
When a function is called normally, this behavior depends on strict mode. In non-strict mode, this refers to the global object.
this in Strict Mode
In strict mode, if this is undefined or null, it stays as undefined or null. In non-strict mode, JavaScript substitutes undefined/null with the global object.
this Based on Function Call
The value of this is determined by how the function is invoked, not where it's defined.
this Inside Object Methods
When a function is called as a method of an object, this refers to the object that the method is called on.
call, apply, and bind
These methods allow explicitly setting the value of this when calling a function.
this Inside Arrow Functions
Arrow functions do not have their own this. They lexically inherit this from the enclosing scope.
this Inside Nested Arrow Functions
Nested arrow functions continue to inherit this lexically from their parent scope.
this in DOM Events
In DOM event handlers, this refers to the DOM element that received the event when using regular functions.
this Reference Summary
| Context | this Value |
|---|---|
| Global Space | window (browser) / global (Node.js) |
| Regular Function | window/undefined (depends on strict mode) |
| Object Method | The object before the dot |
| Arrow Function | Inherited from parent scope |
| Event Listener | The DOM element (regular function) |
call/apply/bind | Explicitly set value |