JavaScript Complete Guide (2026): ES6+, DOM, Async Programming, APIs & Real-World Projects
Table of Contents
- What is JavaScript?
- Why Learn JavaScript in 2026?
- Features of JavaScript
- History of JavaScript
- JavaScript vs TypeScript
- Setting Up JavaScript
- Variables
- Data Types
- Operators
- Control Flow
- Loops
- Functions
- Arrays
- Objects
- ES6 Features
- DOM Manipulation
- Events
- JSON
- Local Storage
- Fetch API
- Promises
- Async/Await
- Error Handling
- Classes
- Modules
- Node.js Basics
- Best Practices
- Performance Optimization
- Security
- JavaScript Projects
- Interview Questions
- FAQs
- Conclusion
What is JavaScript?
JavaScript is the world's most popular programming language for creating interactive websites and web applications. It powers everything from simple animations to complex applications such as Gmail, Google Maps, Netflix, and many modern AI-powered web platforms.
Unlike HTML, which structures a webpage, and CSS, which styles it, JavaScript adds behavior and interactivity. It allows developers to respond to user actions, fetch live data from servers, validate forms, create animations, and build complete front-end and back-end applications.
Today, JavaScript is no longer limited to browsers. With technologies like Node.js, developers can use JavaScript to build APIs, desktop software, mobile applications, serverless functions, and even Internet of Things (IoT) solutions.
Why Learn JavaScript in 2026?
JavaScript remains one of the most valuable programming languages for developers because of its versatility and widespread adoption.
Key reasons include:
- Runs in every modern web browser without installation.
- Essential for front-end frameworks like React, Vue, Angular, and Svelte.
- Enables full-stack development through Node.js.
- Powers progressive web apps (PWAs) and serverless applications.
- Integrates easily with AI APIs and cloud services.
- Backed by one of the largest open-source ecosystems.
Whether you aim to become a front-end, back-end, or full-stack developer, JavaScript is a foundational skill.
Features of JavaScript
Some of the standout features include:
- Lightweight and interpreted.
- Cross-platform compatibility.
- Dynamic typing.
- Object-oriented programming support.
- Functional programming capabilities.
- Event-driven architecture.
- Asynchronous programming with Promises and Async/Await.
- Massive ecosystem through npm.
- Strong community support.
History of JavaScript
JavaScript was created by Brendan Eich in 1995 in just ten days while working at Netscape. Initially called Mocha, it was later renamed LiveScript and eventually JavaScript for marketing purposes.
Since then, JavaScript has evolved significantly through the ECMAScript standard, introducing modern features such as:
- Arrow functions
- Classes
- Modules
- Async/Await
- Optional chaining
- Nullish coalescing
- Private class fields
Today, JavaScript is continuously updated with new features to improve developer productivity and application performance.
JavaScript vs TypeScript
| Feature | JavaScript | TypeScript |
|---|---|---|
| Typing | Dynamic | Static |
| Compilation | Not required | Required |
| Error Detection | Runtime | Compile time |
| Learning Curve | Easier | Slightly steeper |
| Best For | Beginners, web apps | Large enterprise projects |
If you're just starting, learn JavaScript first. TypeScript builds directly on JavaScript and is much easier to pick up once you're comfortable with the language.
Setting Up JavaScript
You don't need special software to begin writing JavaScript.
Option 1: Browser Console
Open Chrome or Firefox, press F12, and navigate to the Console tab.
console.log("Hello, JavaScript!");
Option 2: HTML File
<!DOCTYPE html> <html> <head> <title>JavaScript Example</title> </head> <body> <h1>Hello JavaScript</h1> <script> console.log("JavaScript Loaded"); </script> </body> </html>
Option 3: External JavaScript File
index.html
<script src="app.js"></script>
app.js
console.log("External JavaScript File");
Separating JavaScript into external files improves maintainability and is the standard practice for real-world projects.
JavaScript Variables
Variables are containers that store values.
JavaScript provides three ways to declare variables.
var
var name = "John"; console.log(name);
Avoid var in modern development because it has function scope and can lead to confusing behavior.
let
let age = 22; console.log(age);
Use let when the variable's value will change.
const
const PI = 3.14159; console.log(PI);
Use const by default for values that should not be reassigned.
Variable Naming Rules
Valid:
let firstName; let userAge; let totalMarks;
Invalid:
let 123name; let class; let user-name;
Choose descriptive names that clearly indicate the variable's purpose.
JavaScript Data Types
JavaScript supports both primitive and reference data types.
String
let language = "JavaScript";
Number
let marks = 95; let price = 499.99;
Boolean
let isLoggedIn = true;
Undefined
let city; console.log(city);
Null
let data = null;
BigInt
const large = 9007199254740991n;
Symbol
const id = Symbol("user");
Object
let student = { name: "Alex", age: 20 };
Objects allow you to group related data and are fundamental to JavaScript programming.
Type Checking
console.log(typeof "Hello"); console.log(typeof 100); console.log(typeof true); console.log(typeof {}); console.log(typeof []);
Remember that typeof [] returns "object", which is a well-known quirk of JavaScript.
Operators
Arithmetic Operators
let a = 20; let b = 5; console.log(a + b); console.log(a - b); console.log(a * b); console.log(a / b); console.log(a % b); console.log(a ** b);
Assignment Operators
let x = 10; x += 5; x -= 2; x *= 3; x /= 2;
Comparison Operators
console.log(10 == "10"); console.log(10 === "10"); console.log(20 != 10); console.log(20 > 15); console.log(15 <= 20);
Prefer strict equality (===) because it avoids implicit type conversion.
Logical Operators
let age = 25; let citizen = true; console.log(age >= 18 && citizen); console.log(age < 18 || citizen); console.log(!citizen);
Control Flow
JavaScript uses conditional statements to execute different code paths based on conditions.
if Statement
let marks = 82; if (marks >= 40) { console.log("Pass"); }
if...else
let temperature = 30; if (temperature > 25) { console.log("Hot Weather"); } else { console.log("Cool Weather"); }
else if Ladder
let score = 91; if (score >= 90) { console.log("Grade A"); } else if (score >= 75) { console.log("Grade B"); } else if (score >= 60) { console.log("Grade C"); } else { console.log("Grade D"); }
switch Statement
let day = 3; switch (day) { case 1: console.log("Monday"); break; case 2: console.log("Tuesday"); break; case 3: console.log("Wednesday"); break; default: console.log("Invalid Day"); }
Loops
Loops allow you to execute a block of code repeatedly.
for Loop
for (let i = 1; i <= 5; i++) { console.log(i); }
while Loop
let count = 1; while (count <= 5) { console.log(count); count++; }
do...while Loop
let num = 1; do { console.log(num); num++; } while (num <= 5);
In this part, we'll cover the building blocks of every JavaScript program: variables, data types, operators, type conversion, template literals, and user input. Mastering these concepts will make the advanced topics later in the guide much easier.
Variables in JavaScript
Variables are named containers used to store data. Instead of repeating the same value throughout your code, you store it in a variable and reuse it whenever needed.
Think of a variable as a labeled box:
Name ─────► "John" Age ──────► 25 Salary ───► 55000
Whenever the value changes, the variable points to the new value.
Ways to Declare Variables
Modern JavaScript provides three keywords:
-
let -
const -
var
1. let
Use let when the variable's value may change later.
let age = 22; console.log(age); age = 23; console.log(age);
Output
22 23
Example
let score = 10; score = score + 5; console.log(score);
Output
15
2. const
Use const for values that should never be reassigned.
const PI = 3.14159; console.log(PI);
Attempting to change it results in an error.
const country = "India"; country = "USA";
Output
TypeError
Good Uses of const
const company = "Google"; const TAX_RATE = 18; const API_URL = "https://example.com/api";
Whenever possible, prefer const because it makes code easier to reason about.
3. var
var is the old way of declaring variables.
var name = "John";
Although it still works, modern JavaScript development generally favors let and const because they have more predictable scoping behavior and help prevent common bugs.
Difference Between var, let, and const
| Feature | var | let | const |
|---|---|---|---|
| Scope | Function | Block | Block |
| Can Reassign | Yes | Yes | No |
| Can Redeclare | Yes | No | No |
| Hoisted | Yes | Yes | Yes |
| Modern Recommendation | No | Yes | Yes |
Variable Naming Rules
Valid
let studentName; let totalMarks; let _count; let $price; let user1;
Invalid
let 1name; let my-name; let let; let user name;
Variable Naming Best Practices
Good
let firstName; let totalPrice; let customerAge; let isLoggedIn;
Bad
let a; let b; let xyz; let temp1;
Choose descriptive names so your code is easier to understand.
JavaScript Data Types
Every value in JavaScript has a data type.
The two main categories are:
Data Types ├── Primitive └── Non-Primitive
Primitive Data Types
JavaScript has seven primitive data types.
Number
Stores integers and floating-point numbers.
let age = 25; let marks = 92.5; console.log(age); console.log(marks);
Output
25 92.5
String
Represents text.
let language = "JavaScript"; let city = 'Delhi'; console.log(language); console.log(city);
Output
JavaScript Delhi
Boolean
Stores true or false.
let isStudent = true; let isLoggedIn = false;
Example
console.log(isStudent);
Output
true
Undefined
A variable that has been declared but not assigned a value.
let data; console.log(data);
Output
undefined
Null
Represents an intentional absence of a value.
let user = null; console.log(user);
Output
null
BigInt
Used for very large integers beyond the safe limit of the standard Number type.
let bigNumber = 1234567890123456789012345678901234567890n; console.log(bigNumber);
Symbol
Creates unique identifiers.
let id1 = Symbol("id"); let id2 = Symbol("id"); console.log(id1 === id2);
Output
false
Non-Primitive Data Types
These are reference types.
Main examples include:
- Objects
- Arrays
- Functions
- Dates
- Maps
- Sets
Object
Objects store related information using key-value pairs.
let student = { name: "Rahul", age: 20, course: "BCA" }; console.log(student);
Output
{ name: "Rahul", age: 20, course: "BCA" }
Access values
console.log(student.name); console.log(student.age);
Array
Arrays store multiple values.
let colors = [ "Red", "Blue", "Green" ]; console.log(colors);
Output
["Red","Blue","Green"]
Access items
console.log(colors[0]); console.log(colors[2]);
Output
Red Green
Function
Functions are reusable blocks of code.
function greet(){ console.log("Welcome"); } greet();
Output
Welcome
Functions will be explored in depth later in this guide.
Checking Data Types
JavaScript provides the typeof operator.
let age = 25; console.log(typeof age);
Output
number
More examples
console.log(typeof "Hello"); console.log(typeof true); console.log(typeof []); console.log(typeof {});
Output
string boolean object object
Important Note
Arrays also return "object" with typeof, which is a well-known behavior in JavaScript.
To specifically check for an array:
let items = [1, 2, 3]; console.log(Array.isArray(items));
Output
true
JavaScript Operators
Operators perform operations on values.
Main categories:
- Arithmetic
- Assignment
- Comparison
- Logical
- Increment/Decrement
- Ternary
- Nullish Coalescing
- Optional Chaining (used with objects)
Arithmetic Operators
let a = 20; let b = 5; console.log(a + b); console.log(a - b); console.log(a * b); console.log(a / b); console.log(a % b); console.log(a ** b);
Output
25 15 100 4 0 3200000
Operator meanings:
| Operator | Description |
|---|---|
| + | Addition |
| - | Subtraction |
| * | Multiplication |
| / | Division |
| % | Modulus (remainder) |
| ** | Exponentiation |
Assignment Operators
let x = 10; x += 5; console.log(x);
Output
15
Other assignment operators include:
x -= 2; x *= 3; x /= 2; x %= 2;
Comparison Operators
Comparison operators return a boolean value (true or false).
console.log(10 > 5); console.log(10 < 5); console.log(10 >= 10); console.log(10 <= 8); console.log(10 == "10"); console.log(10 === "10"); console.log(10 != 20); console.log(10 !== "10");
Output
true false true false true false true true
== vs ===
console.log(5 == "5");
Output
true
Because == performs type coercion.
console.log(5 === "5");
Output
false
=== checks both value and data type, making it the preferred choice in modern JavaScript.
Logical Operators
Logical operators are commonly used in conditions.
let age = 20; let hasLicense = true; console.log(age >= 18 && hasLicense);
Output
true
Examples
console.log(true || false); console.log(!true);
Output
true false
Increment and Decrement Operators
let count = 5; count++; console.log(count);
Output
6
count--; console.log(count);
Output
5
Type Conversion
JavaScript can convert values between different data types.
String to Number
let marks = "95"; console.log(Number(marks));
Output
95
Number to String
let age = 21; console.log(String(age));
Output
"21"
Boolean Conversion
console.log(Boolean(1)); console.log(Boolean(0)); console.log(Boolean(""));
Output
true false false
Common truthy values include non-empty strings, non-zero numbers, arrays, and objects. Common falsy values include false, 0, "", null, undefined, and NaN.
Template Literals
Template literals make string creation cleaner and more readable.
Old style
let name = "Alice"; console.log("Hello " + name);
Modern style
let name = "Alice"; console.log(`Hello ${name}`);
Output
Hello Alice
You can also embed expressions.
let a = 10; let b = 20; console.log(`Sum = ${a + b}`);
Output
Sum = 30
Template literals also support multi-line strings.
let message = `Welcome to the JavaScript Complete Guide`; console.log(message);
Getting User Input
In the browser, you can use prompt() to receive input from the user.
let name = prompt("Enter your name:"); console.log(name);
You can combine it with template literals.
let city = prompt("Enter your city:"); console.log(`You live in ${city}.`);
Note: prompt() is available in browsers but not in Node.js by default.
Common Beginner Mistakes
-
Using
varinstead ofletorconstin new code. -
Using
==when===is the safer choice. -
Forgetting that
prompt()returns a string. -
Reassigning a
constvariable. -
Choosing vague variable names like
xortempfor important data. -
Confusing
nullandundefined.
Practice Exercises
- Create variables for your name, age, and favorite programming language, then print them.
- Calculate the area of a rectangle using variables for length and width.
-
Convert the string
"150"into a number and add50. - Use template literals to display your profile in one sentence.
- Compare two numbers using all comparison operators.
-
Create an object representing a book with
title,author, andprice. - Create an array of five programming languages and print the third one.
-
Use
typeofon every primitive data type. - Write a program that increments a counter five times.
-
Ask the user for their name using
prompt()and greet them.
Now that you understand variables, data types, and operators, it's time to make your programs intelligent. In this part, you'll learn how JavaScript makes decisions, repeats tasks efficiently, and controls program execution using conditions and loops.
Control Flow in JavaScript
Control flow determines the order in which JavaScript executes statements.
Without control flow, every line of code would run from top to bottom. In real applications, we often need to:
- Make decisions
- Repeat tasks
- Skip certain operations
- Stop execution when a condition is met
Control flow provides these capabilities.
Start │ ▼ Condition? ┌───────┐ │ True │────► Execute Block A └───────┘ │ ▼ ┌───────┐ │ False │────► Execute Block B └───────┘ │ ▼ Continue Program
The if Statement
The if statement executes a block of code only if a condition evaluates to true.
Syntax
if (condition) { // code }
Example
let age = 20; if (age >= 18) { console.log("You are eligible to vote."); }
Output
You are eligible to vote.
Another Example
let temperature = 35; if (temperature > 30) { console.log("It's a hot day."); }
Output
It's a hot day.
if...else Statement
Use if...else when there are two possible outcomes.
let marks = 40; if (marks >= 35) { console.log("Pass"); } else { console.log("Fail"); }
Output
Pass
Example: Login System
let password = "admin123"; if (password === "admin123") { console.log("Login Successful"); } else { console.log("Invalid Password"); }
Output
Login Successful
else if Statement
Use else if when checking multiple conditions.
let marks = 88; if (marks >= 90) { console.log("Grade A+"); } else if (marks >= 80) { console.log("Grade A"); } else if (marks >= 70) { console.log("Grade B"); } else if (marks >= 60) { console.log("Grade C"); } else { console.log("Fail"); }
Output
Grade A
Real Example: Income Tax Category
let income = 850000; if (income < 300000) { console.log("No Tax"); } else if (income < 700000) { console.log("5% Tax"); } else if (income < 1200000) { console.log("10% Tax"); } else { console.log("20% Tax"); }
Nested if Statements
An if statement can contain another if statement.
let age = 24; let hasLicense = true; if (age >= 18) { if (hasLicense) { console.log("You can drive."); } }
Output
You can drive.
Truthy and Falsy Values
JavaScript doesn't always require a boolean in conditions.
Example
let username = "Alice"; if (username) { console.log("Welcome!"); }
Output
Welcome!
Falsy values include:
- false
- 0
- ""
- null
- undefined
- NaN
Everything else is generally considered truthy.
switch Statement
switch is useful when comparing one value against many fixed options.
Syntax
switch(expression){ case value1: // code break; case value2: // code break; default: // code }
Example
let day = 3; switch(day){ case 1: console.log("Monday"); break; case 2: console.log("Tuesday"); break; case 3: console.log("Wednesday"); break; default: console.log("Invalid Day"); }
Output
Wednesday
Calculator Example
let operation = "+"; switch(operation){ case "+": console.log(15 + 10); break; case "-": console.log(15 - 10); break; case "*": console.log(15 * 10); break; case "/": console.log(15 / 10); break; default: console.log("Invalid Operator"); }
Ternary Operator
A shorter alternative to if...else.
Syntax
condition ? value1 : value2
Example
let age = 20; let result = age >= 18 ? "Adult" : "Minor"; console.log(result);
Output
Adult
Another Example
let number = 7; console.log(number % 2 === 0 ? "Even" : "Odd");
Output
Odd
for Loop
The for loop repeats code a fixed number of times.
Syntax
for(initialization; condition; update){ // code }
Example
for(let i = 1; i <= 5; i++){ console.log(i); }
Output
1 2 3 4 5
Print Squares
for(let i = 1; i <= 10; i++){ console.log(i * i); }
Output
1 4 9 16 25 36 49 64 81 100
Sum of Numbers
let sum = 0; for(let i = 1; i <= 100; i++){ sum += i; } console.log(sum);
Output
5050
while Loop
Runs while a condition is true.
let i = 1; while(i <= 5){ console.log(i); i++; }
Output
1 2 3 4 5
Countdown Example
let countdown = 10; while(countdown > 0){ console.log(countdown); countdown--; } console.log("Lift Off!");
do...while Loop
Runs at least once.
let number = 1; do{ console.log(number); number++; } while(number <= 5);
Output
1 2 3 4 5
Difference Between while and do...while
| while | do...while |
|---|---|
| Checks condition first | Executes once before checking |
| May never execute | Executes at least once |
Infinite Loops
Incorrect
while(true){ console.log("Hello"); }
This loop never stops and should generally be avoided unless you intentionally provide a way to exit it.
break Statement
Stops a loop immediately.
for(let i = 1; i <= 10; i++){ if(i === 6){ break; } console.log(i); }
Output
1 2 3 4 5
continue Statement
Skips the current iteration.
for(let i = 1; i <= 5; i++){ if(i === 3){ continue; } console.log(i); }
Output
1 2 4 5
Nested Loops
A loop inside another loop.
for(let i = 1; i <= 3; i++){ for(let j = 1; j <= 3; j++){ console.log(i, j); } }
Output
1 1 1 2 1 3 2 1 2 2 2 3 3 1 3 2 3 3
Pattern Printing Example
for(let i = 1; i <= 5; i++){ let stars = ""; for(let j = 1; j <= i; j++){ stars += "*"; } console.log(stars); }
Output
* ** *** **** *****
Looping Through Arrays
let languages = [ "JavaScript", "Python", "Java", "C++" ]; for(let i = 0; i < languages.length; i++){ console.log(languages[i]); }
Output
JavaScript Python Java C++
for...of Loop
Best for iterating over arrays and other iterable objects.
const colors = ["Red", "Green", "Blue"]; for (const color of colors) { console.log(color); }
Output
Red Green Blue
for...in Loop
Used for iterating over object properties.
const student = { name: "Rahul", age: 20, course: "BCA" }; for (const key in student) { console.log(key, student[key]); }
Output
name Rahul age 20 course BCA
Tip: Prefer
for...offor arrays andfor...infor objects.
Optional Chaining (?.)
Optional chaining prevents runtime errors when accessing nested properties that may not exist.
const user = { profile: { name: "Alice" } }; console.log(user.profile?.name); console.log(user.address?.city);
Output
Alice undefined
Without optional chaining, accessing user.address.city would throw an error.
Nullish Coalescing (??)
The nullish coalescing operator provides a default value only when the left-hand side is null or undefined.
let username = null; console.log(username ?? "Guest");
Output
Guest
Compare it with the logical OR operator:
console.log("" || "Default"); console.log("" ?? "Default");
Output
Default ""
This makes ?? a better choice when empty strings or 0 are valid values.
Practical Exercise: Multiplication Table
let number = 7; for (let i = 1; i <= 10; i++) { console.log(`${number} x ${i} = ${number * i}`); }
Output
7 x 1 = 7 ... 7 x 10 = 70
Practice Exercises
- Check whether a number is positive, negative, or zero.
-
Find the largest of three numbers using
if...else. - Print all even numbers from 1 to 100.
- Calculate the factorial of a number using a loop.
- Reverse the digits of an integer.
- Count the number of vowels in a string.
-
Print the Fibonacci sequence up to
nterms. -
Create a simple menu using
switch. - Generate different star patterns using nested loops.
-
Iterate through an object using
for...inand an array usingfor...of.
Functions are the foundation of modern JavaScript. Every framework, library, API, and application relies heavily on functions. In this part, you'll learn how to write reusable code, understand scope, use modern ES6+ syntax, and explore concepts like closures and higher-order functions that are frequently asked in interviews.
What is a Function?
A function is a reusable block of code designed to perform a specific task. Instead of writing the same logic multiple times, you write it once and call it whenever needed.
Why Use Functions?
Functions help you:
- Reuse code
- Improve readability
- Reduce duplication
- Organize large applications
- Simplify debugging and maintenance
Without functions, even small applications become difficult to manage.
Function Declaration
A function declaration is the most common way to define a function.
Syntax
function functionName(parameters) { // code }
Example
function greet() { console.log("Welcome to JavaScript!"); } greet();
Output
Welcome to JavaScript!
Functions with Parameters
Parameters allow you to pass data into a function.
function greet(name) { console.log("Hello " + name); } greet("Alice"); greet("Rahul"); greet("John");
Output
Hello Alice Hello Rahul Hello John
Multiple Parameters
function add(a, b) { console.log(a + b); } add(10, 20); add(5, 8);
Output
30 13
Returning Values
Functions can return data using the return keyword.
function multiply(a, b) { return a * b; } let result = multiply(8, 5); console.log(result);
Output
40
Why Return Instead of console.log()?
Consider the following:
function square(number) { return number * number; } let answer = square(6); console.log(answer + 10);
Output
46
Returning values allows other parts of your program to reuse the result.
Function Expressions
Functions can also be assigned to variables.
const greet = function() { console.log("Hello!"); }; greet();
Output
Hello!
Anonymous Functions
Functions without names are called anonymous functions.
const message = function() { console.log("Anonymous Function"); }; message();
Arrow Functions (ES6)
Arrow functions provide a shorter syntax.
Traditional
function add(a, b){ return a + b; }
Arrow
const add = (a, b) => { return a + b; };
Single Parameter
const square = number => { return number * number; }; console.log(square(5));
Output
25
One-Line Arrow Function
const cube = number => number * number * number; console.log(cube(3));
Output
27
Default Parameters
Default values are used when an argument is not provided.
function greet(name = "Guest"){ console.log("Welcome " + name); } greet(); greet("Alice");
Output
Welcome Guest Welcome Alice
Rest Parameters
Rest parameters collect multiple arguments into an array.
function total(...numbers){ let sum = 0; for(const number of numbers){ sum += number; } return sum; } console.log(total(5,10,15,20));
Output
50
Spread Operator
The spread operator expands arrays or objects.
const numbers = [10,20,30]; console.log(...numbers);
Output
10 20 30
Copy arrays
const original = [1,2,3]; const copy = [...original]; console.log(copy);
Output
[1,2,3]
Merge arrays
const frontend = [ "HTML", "CSS" ]; const backend = [ "Node.js", "MongoDB" ]; const fullstack = [ ...frontend, "JavaScript", ...backend ]; console.log(fullstack);
Output
["HTML","CSS","JavaScript","Node.js","MongoDB"]
Function Scope
Variables exist only within certain parts of your program.
JavaScript has:
- Global Scope
- Function Scope
- Block Scope
Global Scope
let language = "JavaScript"; function show(){ console.log(language); } show();
Output
JavaScript
Local Scope
function test(){ let message = "Hello"; console.log(message); } test();
Trying to access message outside the function results in an error.
Block Scope
Variables declared using let and const exist only inside the block where they are defined.
if(true){ let score = 100; console.log(score); }
Outside the block:
console.log(score);
Output
ReferenceError
Hoisting
JavaScript moves declarations to the top of their scope during compilation.
Example
greet(); function greet(){ console.log("Hello"); }
Output
Hello
However, function expressions and arrow functions are not initialized in the same way.
sayHello(); const sayHello = () => { console.log("Hi"); };
Output
ReferenceError
Callback Functions
A callback is a function passed as an argument to another function.
function welcome(name){ console.log("Welcome " + name); } function process(callback){ callback("Alice"); } process(welcome);
Output
Welcome Alice
Callbacks are widely used in asynchronous programming, event handling, and APIs.
Higher-Order Functions
A higher-order function either:
- Accepts another function as an argument, or
- Returns a function.
Example
function calculator(operation){ return operation(10,5); } function add(a,b){ return a+b; } console.log(calculator(add));
Output
15
Closures
A closure occurs when an inner function remembers variables from its outer function even after the outer function has finished executing.
function counter(){ let count = 0; return function(){ count++; console.log(count); }; } const increment = counter(); increment(); increment(); increment();
Output
1 2 3
Closures are commonly used for:
- Data privacy
- State management
- Function factories
- Event handlers
Immediately Invoked Function Expression (IIFE)
An IIFE runs immediately after it is defined.
(function(){ console.log("Executed Immediately"); })();
Output
Executed Immediately
IIFEs were commonly used before ES6 modules to avoid polluting the global scope.
Recursive Functions
A recursive function calls itself.
Example: Factorial
function factorial(n){ if(n===0){ return 1; } return n * factorial(n-1); } console.log(factorial(5));
Output
120
Function Overloading?
JavaScript does not support traditional function overloading.
Example
function test(){ console.log("One"); } function test(name){ console.log(name); } test("Alice");
Output
Alice
The second declaration replaces the first one.
Pure Functions
A pure function:
- Produces the same output for the same input.
- Does not modify external state.
- Has no side effects.
function add(a,b){ return a+b; }
Pure functions are easier to test and maintain.
Impure Function
let total = 0; function add(value){ total += value; }
This function modifies external state, making it impure.
First-Class Functions
JavaScript treats functions as first-class citizens.
Functions can be:
- Stored in variables
- Passed as arguments
- Returned from other functions
- Stored inside arrays or objects
Example
const greet = () => "Hello"; const functions = [ greet ]; console.log(functions[0]());
Output
Hello
Practical Example: Simple Calculator
function calculate(a, b, operation){ switch(operation){ case "+": return a+b; case "-": return a-b; case "*": return a*b; case "/": return a/b; default: return "Invalid Operation"; } } console.log(calculate(15,5,"+")); console.log(calculate(15,5,"*"));
Output
20 75
Practical Example: Temperature Converter
const celsiusToFahrenheit = celsius => (celsius * 9/5) + 32; console.log(celsiusToFahrenheit(30));
Output
86
Common Mistakes
❌ Forgetting to return a value.
function add(a,b){ a+b; }
Correct
function add(a,b){ return a+b; }
❌ Calling a function without parentheses.
Incorrect
greet;
Correct
greet();
❌ Using var instead of const or let in modern code.
❌ Confusing function declarations with arrow functions when relying on hoisting.
Interview Questions
What is the difference between parameters and arguments?
- Parameters are variables listed in the function definition.
- Arguments are the actual values passed when calling the function.
What is a callback function?
A function passed as an argument to another function and executed later.
What is a closure?
A closure is an inner function that retains access to variables from its outer lexical scope even after the outer function has returned.
What is a higher-order function?
A function that accepts another function as an argument or returns a function.
Why use arrow functions?
- Shorter syntax
-
Lexical
thisbinding - Cleaner callback code
- Commonly used in React and modern JavaScript
Practice Exercises
- Write a function to check whether a number is prime.
- Create a function that reverses a string.
- Find the largest element in an array using a function.
- Create an arrow function that calculates the average of three numbers.
- Write a recursive function to generate Fibonacci numbers.
- Build a calculator using functions.
- Create a function that removes duplicate elements from an array.
- Use rest parameters to find the maximum number.
- Write a function that accepts another function as a callback.
- Create a closure that tracks how many times a button has been clicked.
Arrays and objects are the backbone of JavaScript applications. Whether you're building a React application, processing API responses, or managing user data, you'll work with arrays and objects every day. In this section, you'll master modern array methods, object manipulation, ES6 collections, and practical examples used in production applications.
Arrays in JavaScript
An array is an ordered collection of values stored in a single variable.
Instead of creating multiple variables:
let student1 = "Alice"; let student2 = "Bob"; let student3 = "Charlie";
You can use one array:
const students = ["Alice", "Bob", "Charlie"];
Creating Arrays
Using Array Literals (Recommended)
const fruits = ["Apple", "Banana", "Orange"]; console.log(fruits);
Output
["Apple", "Banana", "Orange"]
Using the Array Constructor
const numbers = new Array(10, 20, 30); console.log(numbers);
Output
[10, 20, 30]
Array literals are preferred because they are simpler and more readable.
Accessing Array Elements
Array indexing starts from 0.
const colors = ["Red", "Green", "Blue"];
console.log(colors[0]); console.log(colors[1]); console.log(colors[2]);
Output
Red Green Blue
Modifying Arrays
const languages = [ "Java", "Python", "C++" ]; languages[1] = "JavaScript"; console.log(languages);
Output
["Java","JavaScript","C++"]
Array Length
const numbers = [5,10,15,20]; console.log(numbers.length);
Output
4
Adding Elements
push()
Adds an element to the end.
const cities = [ "Delhi", "Mumbai" ]; cities.push("Pune"); console.log(cities);
Output
["Delhi","Mumbai","Pune"]
unshift()
Adds to the beginning.
cities.unshift("Nagpur"); console.log(cities);
Output
["Nagpur","Delhi","Mumbai","Pune"]
Removing Elements
pop()
Removes the last element.
const numbers = [1,2,3,4]; numbers.pop(); console.log(numbers);
Output
[1,2,3]
shift()
Removes the first element.
numbers.shift(); console.log(numbers);
Output
[2,3]
Finding Elements
includes()
const fruits = [ "Apple", "Banana", "Mango" ]; console.log(fruits.includes("Banana"));
Output
true
indexOf()
console.log(fruits.indexOf("Mango"));
Output
2
If the element is not found:
-1
Joining Arrays
const languages = [ "HTML", "CSS", "JavaScript" ]; console.log(languages.join(" - "));
Output
HTML - CSS - JavaScript
slice()
Returns a portion of an array without modifying the original.
const numbers = [10,20,30,40,50]; console.log(numbers.slice(1,4));
Output
[20,30,40]
Original array remains unchanged.
splice()
Adds or removes elements by modifying the original array.
const numbers = [10,20,30,40]; numbers.splice(2,1); console.log(numbers);
Output
[10,20,40]
Looping Through Arrays
Classic for loop
const colors = [ "Red", "Green", "Blue" ]; for(let i=0;i<colors.length;i++){ console.log(colors[i]); }
for...of
for(const color of colors){ console.log(color); }
This is the preferred approach for arrays.
forEach()
Executes a callback for every element.
const numbers = [10,20,30]; numbers.forEach(function(number){ console.log(number); });
Output
10 20 30
Arrow function version
numbers.forEach(number => console.log(number));
map()
Creates a new array by transforming each element.
const prices = [100,200,300]; const discounted = prices.map(price => price * 0.9); console.log(discounted);
Output
[90,180,270]
Original array remains unchanged.
Real Example
const users = [ {name:"Alice"}, {name:"Bob"}, {name:"John"} ]; const names = users.map(user => user.name); console.log(names);
Output
["Alice","Bob","John"]
filter()
Returns only elements matching a condition.
const ages = [15,18,25,12,40]; const adults = ages.filter(age => age >= 18); console.log(adults);
Output
[18,25,40]
reduce()
Reduces an array to a single value.
const numbers = [10,20,30]; const total = numbers.reduce((sum,number)=>{ return sum + number; },0); console.log(total);
Output
60
Real Example: Shopping Cart
const cart = [ {price:500}, {price:300}, {price:200} ]; const totalPrice = cart.reduce((total,item)=>{ return total + item.price; },0); console.log(totalPrice);
Output
1000
find()
Returns the first matching element.
const users = [ {name:"Alice"}, {name:"Bob"}, {name:"Charlie"} ]; const user = users.find(user=>user.name==="Bob"); console.log(user);
Output
{name:"Bob"}
findIndex()
const numbers = [15,30,45,60]; console.log(numbers.findIndex(number=>number===45));
Output
2
some()
Returns true if at least one element satisfies the condition.
const marks = [45,60,80]; console.log(marks.some(mark=>mark>=75));
Output
true
every()
Returns true only if every element satisfies the condition.
console.log(marks.every(mark=>mark>=35));
Output
true
sort()
Default sorting.
const names = [ "John", "Alice", "David" ]; names.sort(); console.log(names);
Output
["Alice","David","John"]
Sorting Numbers
Incorrect
const numbers = [10,2,50]; numbers.sort(); console.log(numbers);
Output
[10,2,50]
Correct
numbers.sort((a,b)=>a-b); console.log(numbers);
Output
[2,10,50]
Descending
numbers.sort((a,b)=>b-a);
reverse()
const numbers = [1,2,3]; numbers.reverse(); console.log(numbers);
Output
[3,2,1]
flat()
Flattens nested arrays.
const values = [ 1, 2, [3,4], [5,[6]] ]; console.log(values.flat()); console.log(values.flat(2));
Output
[1,2,3,4,5,[6]] [1,2,3,4,5,6]
Objects in JavaScript
Objects store data using key-value pairs.
const student = { name:"Rahul", age:20, course:"BCA" };
Accessing Properties
Dot notation
console.log(student.name);
Bracket notation
console.log(student["course"]);
Updating Properties
student.age = 21; console.log(student);
Adding Properties
student.city = "Nagpur"; console.log(student);
Deleting Properties
delete student.course;
Object Methods
const person = { name:"Alice", greet(){ console.log("Hello " + this.name); } }; person.greet();
Output
Hello Alice
Object.keys()
console.log(Object.keys(student));
Output
["name","age","city"]
Object.values()
console.log(Object.values(student));
Output
["Rahul",21,"Nagpur"]
Object.entries()
console.log(Object.entries(student));
Output
[ ["name","Rahul"], ["age",21], ["city","Nagpur"] ]
Destructuring Arrays
const colors = [ "Red", "Green", "Blue" ]; const [first,second] = colors; console.log(first); console.log(second);
Output
Red Green
Object Destructuring
const user = { name:"Alice", age:25 }; const {name,age} = user; console.log(name); console.log(age);
Renaming Variables During Destructuring
const {name:username} = user; console.log(username);
Spread Operator with Objects
const student = { name:"Rahul", age:20 }; const updatedStudent = { ...student, city:"Nagpur" }; console.log(updatedStudent);
ES6 Map
A Map stores key-value pairs and allows keys of any type.
const userRoles = new Map(); userRoles.set("Alice", "Admin"); userRoles.set("Bob", "Editor"); userRoles.set(101, "Guest"); console.log(userRoles.get("Alice")); console.log(userRoles.has("Bob")); console.log(userRoles.size);
Output
Admin true 3
Iterating over a Map:
for (const [user, role] of userRoles) { console.log(user, role); }
ES6 Set
A Set stores only unique values.
const uniqueNumbers = new Set([1, 2, 2, 3, 4, 4]); console.log(uniqueNumbers);
Output
Set(4) {1, 2, 3, 4}
Adding and removing values:
uniqueNumbers.add(5); uniqueNumbers.delete(2); console.log(uniqueNumbers.has(3));
Removing Duplicate Values
One of the most common real-world uses of Set:
const numbers = [1, 2, 2, 3, 4, 4, 5]; const unique = [...new Set(numbers)]; console.log(unique);
Output
[1, 2, 3, 4, 5]
Immutable Array Methods (Modern JavaScript)
Newer JavaScript versions introduced non-mutating alternatives that return new arrays instead of changing the original.
const numbers = [3, 1, 2]; const sorted = numbers.toSorted(); console.log(numbers); console.log(sorted);
Output
[3, 1, 2] [1, 2, 3]
Other useful immutable methods include:
-
toReversed() -
toSpliced() -
with()
These help avoid accidental mutations, especially in frameworks like React.
Practical Example: Student Result Analysis
const students = [ { name: "Alice", marks: 92 }, { name: "Bob", marks: 68 }, { name: "Charlie", marks: 81 }, { name: "David", marks: 55 } ]; const passedStudents = students.filter(student => student.marks >= 60); const studentNames = passedStudents.map(student => student.name); const averageMarks = students.reduce((sum, student) => sum + student.marks, 0) / students.length; console.log(passedStudents); console.log(studentNames); console.log(averageMarks);
Common Mistakes
❌ Using map() when you don't use the returned array.
❌ Modifying arrays unexpectedly with sort(), reverse(), or splice().
❌ Forgetting that objects are assigned by reference.
❌ Using for...in to iterate over arrays instead of for...of.
❌ Forgetting that filter() always returns an array, even if only one item matches.
Interview Questions
What is the difference between map() and forEach()?
-
map()returns a new transformed array. -
forEach()executes a callback but returnsundefined.
When should you use reduce()?
Use reduce() when you need to combine an array into a single value, such as a total, average, grouped object, or flattened structure.
What is the difference between Map and a plain object?
-
Mapaccepts keys of any type. -
Mappreserves insertion order and provides convenient methods likeset(),get(),has(), anddelete(). - Plain objects are primarily designed for structured data with string or symbol keys.
Why use Set?
A Set automatically stores only unique values, making it useful for removing duplicates and membership checks.
Practice Exercises
- Find the highest and lowest numbers in an array.
- Remove duplicate values from an array.
- Sort an array of objects by age.
-
Calculate the average salary of employees using
reduce(). -
Convert an array of user objects into an array of usernames using
map(). - Filter products that cost more than ₹1000.
- Count how many times each word appears in an array.
- Merge two objects using the spread operator.
-
Build a simple phone book using
Map. -
Create a unique list of programming languages using
Set.
This is where JavaScript becomes truly interactive. So far, you've learned how to write JavaScript programs. Now you'll learn how JavaScript communicates with web pages using the Document Object Model (DOM).
DOM manipulation is one of the most important skills for frontend development. Every modern framework—including React, Angular, Vue, and Svelte—is built on DOM concepts.
By the end of this section, you'll be able to build interactive web pages, validate forms, create dynamic content, handle user events, and store data in the browser.
What is the DOM?
The Document Object Model (DOM) is a programming interface that represents an HTML document as a tree of objects.
Instead of treating an HTML page as plain text, the browser converts it into a structure that JavaScript can read and modify.
For example, consider this HTML:
<!DOCTYPE html> <html> <head> <title>My Website</title> </head> <body> <h1>Welcome</h1> <p>Learning JavaScript</p> </body> </html>
The browser represents it like this:
Document │ ├── html │ ├── head │ └── title │ └── body ├── h1 └── p
Every HTML element becomes a JavaScript object.
Why is the DOM Important?
Without the DOM, websites would remain static.
The DOM enables JavaScript to:
- Change text
- Change images
- Change CSS styles
- Add new HTML elements
- Remove existing elements
- Validate forms
- Respond to button clicks
- Animate elements
- Build interactive applications
Modern websites rely heavily on these capabilities.
Selecting HTML Elements
Before changing an element, JavaScript must locate it.
getElementById()
HTML
<h1 id="title">JavaScript Guide</h1>
JavaScript
const heading = document.getElementById("title"); console.log(heading);
getElementsByClassName()
HTML
<p class="info">First</p> <p class="info">Second</p>
JavaScript
const items = document.getElementsByClassName("info"); console.log(items);
Returns an HTMLCollection.
getElementsByTagName()
const paragraphs = document.getElementsByTagName("p"); console.log(paragraphs);
querySelector()
The most commonly used selector.
Selects the first matching element.
HTML
<div class="card"> JavaScript </div>
JavaScript
const card = document.querySelector(".card"); console.log(card);
querySelectorAll()
Returns all matching elements.
const cards = document.querySelectorAll(".card"); console.log(cards);
Output
NodeList(3)
Example
cards.forEach(card => { console.log(card); });
Reading Content
Suppose the HTML is:
<h1 id="title"> JavaScript Tutorial </h1>
Read text
const title = document.getElementById("title"); console.log(title.textContent);
Output
JavaScript Tutorial
textContent vs innerText
Both return text, but they behave differently.
element.textContent
- Returns all text
- Includes hidden text
- Faster
element.innerText
- Returns visible text only
- Respects CSS visibility
- Slightly slower
In most situations, textContent is the better choice.
innerHTML
Returns HTML inside an element.
<div id="content"> <b>Hello</b> </div>
const content = document.getElementById("content"); console.log(content.innerHTML);
Output
<b>Hello</b>
Updating HTML
content.innerHTML = "<h2>Updated Content</h2>";
⚠️ Security Tip: Avoid inserting untrusted user input directly with innerHTML, as it can lead to Cross-Site Scripting (XSS) vulnerabilities. Prefer textContent when you only need to display text.
Changing Text
const heading = document.querySelector("h1"); heading.textContent = "Modern JavaScript";
Before
JavaScript Guide
After
Modern JavaScript
Changing CSS Styles
const heading = document.querySelector("h1"); heading.style.color = "blue"; heading.style.fontSize = "40px"; heading.style.backgroundColor = "yellow";
Although inline styles work, using CSS classes is generally cleaner for larger projects.
Working with CSS Classes
Instead of directly modifying styles, use classList.
HTML
<div id="box" class="card"> Content </div>
Add class
box.classList.add("active");
Remove class
box.classList.remove("active");
Toggle class
box.classList.toggle("dark");
Check class
box.classList.contains("card");
Output
true
Changing Attributes
HTML
<img id="logo" src="old.png">
JavaScript
const image = document.getElementById("logo"); image.setAttribute("src", "new.png");
Read attribute
console.log(image.getAttribute("src"));
Remove attribute
image.removeAttribute("src");
Creating HTML Elements
Create a paragraph
const paragraph = document.createElement("p"); paragraph.textContent = "This paragraph was created dynamically.";
Nothing appears yet because the element has not been added to the page.
Adding Elements
Append to body
document.body.appendChild(paragraph);
Append to another element
const container = document.querySelector(".container"); container.appendChild(paragraph);
insertAdjacentHTML()
Useful for inserting HTML without replacing existing content.
const list = document.querySelector("#list"); list.insertAdjacentHTML( "beforeend", "<li>New Item</li>" );
Possible positions:
-
beforebegin -
afterbegin -
beforeend -
afterend
Removing Elements
const element = document.querySelector(".old"); element.remove();
Replacing Elements
const oldElement = document.querySelector("#old"); const newElement = document.createElement("h2"); newElement.textContent = "New Heading"; oldElement.replaceWith(newElement);
Event Handling
Events allow JavaScript to respond to user actions.
Common events include:
- click
- dblclick
- mouseover
- mouseout
- keydown
- keyup
- input
- submit
- change
- focus
- blur
Click Event
HTML
<button id="btn"> Click Me </button>
JavaScript
const button = document.getElementById("btn"); button.addEventListener("click", function(){ console.log("Button Clicked"); });
Output after clicking
Button Clicked
Arrow Function Event
button.addEventListener("click", ()=>{ alert("Welcome!"); });
Mouse Events
const box = document.querySelector(".box"); box.addEventListener("mouseover", ()=>{ console.log("Mouse Entered"); }); box.addEventListener("mouseout", ()=>{ console.log("Mouse Left"); });
Keyboard Events
document.addEventListener("keydown", (event)=>{ console.log(event.key); });
Pressing
A
Outputs
a
Useful properties:
-
event.key -
event.code -
event.ctrlKey -
event.shiftKey -
event.altKey
Input Event
<input id="username">
const input = document.getElementById("username"); input.addEventListener("input",(event)=>{ console.log(event.target.value); });
This updates every time the user types.
Form Handling
HTML
<form id="loginForm"> <input type="text" id="name"> <button> Submit </button> </form>
JavaScript
const form = document.getElementById("loginForm"); form.addEventListener("submit",(event)=>{ event.preventDefault(); console.log("Form Submitted"); });
event.preventDefault() prevents the browser from reloading the page.
Basic Form Validation
const nameInput = document.getElementById("name"); if(nameInput.value.trim()===""){ alert("Name Required"); }
More complete example:
form.addEventListener("submit", (event) => { event.preventDefault(); const name = nameInput.value.trim(); if (name === "") { alert("Please enter your name."); return; } console.log(`Welcome, ${name}!`); });
Event Delegation
Instead of adding an event listener to every child element, attach one listener to the parent.
const list = document.querySelector("#todoList"); list.addEventListener("click", (event) => { if (event.target.matches("li")) { console.log(event.target.textContent); } });
This approach improves performance when working with many dynamic elements.
DOM Traversal
Example HTML
<div id="parent"> <p>First</p> <p>Second</p> </div>
JavaScript
const parent = document.getElementById("parent"); console.log(parent.children); console.log(parent.firstElementChild); console.log(parent.lastElementChild);
Other useful properties:
element.parentElement element.nextElementSibling element.previousElementSibling
Local Storage
Local Storage stores data even after the browser closes.
Save
localStorage.setItem("username","Alice");
Read
console.log(localStorage.getItem("username"));
Delete one
localStorage.removeItem("username");
Delete everything
localStorage.clear();
Storing Objects in Local Storage
Since Local Storage stores strings, convert objects to JSON.
const user = { name:"Alice", age:25 }; localStorage.setItem( "user", JSON.stringify(user) );
Retrieve
const storedUser = JSON.parse( localStorage.getItem("user") ); console.log(storedUser);
Session Storage
Works similarly to Local Storage but is cleared when the browser tab is closed.
sessionStorage.setItem("theme","dark"); console.log(sessionStorage.getItem("theme"));
Browser Timers
setTimeout()
Runs code once after a delay.
setTimeout(() => { console.log("Executed after 2 seconds"); }, 2000);
setInterval()
Runs repeatedly until stopped.
const timer = setInterval(() => { console.log("Tick"); }, 1000);
Stop it
clearInterval(timer);
Mini Project: Live Character Counter
HTML
<textarea id="message"></textarea> <p>Characters: <span id="count">0</span></p>
JavaScript
const textarea = document.getElementById("message"); const count = document.getElementById("count"); textarea.addEventListener("input",()=>{ count.textContent = textarea.value.length; });
Features
- Live updates
- Event handling
- DOM manipulation
- User interaction
Mini Project: Dark Mode Toggle
HTML
<button id="themeBtn">Toggle Theme</button>
JavaScript
const themeBtn = document.getElementById("themeBtn"); themeBtn.addEventListener("click", () => { document.body.classList.toggle("dark-mode"); });
CSS
.dark-mode { background-color: #222; color: white; }
Common Mistakes
❌ Using innerHTML for plain text.
❌ Forgetting preventDefault() in form submissions.
❌ Adding hundreds of individual event listeners instead of using event delegation.
❌ Forgetting to parse JSON retrieved from Local Storage.
❌ Attempting to access DOM elements before they exist. Place your script at the end of the <body> or wait for the DOMContentLoaded event.
Interview Questions
What is the DOM?
A tree-like representation of an HTML document that JavaScript can manipulate.
Difference between querySelector() and querySelectorAll()?
-
querySelector()returns the first matching element. -
querySelectorAll()returns a staticNodeListof all matching elements.
What is event bubbling?
When an event starts at the target element and propagates upward through its ancestor elements.
Why use addEventListener()?
It allows multiple event listeners on the same element and separates JavaScript behavior from HTML markup.
Difference between Local Storage and Session Storage?
| Local Storage | Session Storage |
|---|---|
| Persists after browser restart | Cleared when the tab closes |
| Larger persistence | Temporary session data |
| Shared across tabs of the same origin | Limited to the current tab |
Practice Exercises
- Build a digital clock.
- Create a color changer using buttons.
- Build a simple image gallery.
- Create a BMI calculator with form validation.
- Develop a to-do list using Local Storage.
- Implement a dark mode toggle that remembers the user's preference.
- Build a live search filter for a list of items.
- Create an accordion (expand/collapse sections).
-
Implement a countdown timer using
setInterval(). - Build a simple notes application that stores notes in Local Storage.
Asynchronous programming is one of the most important concepts in modern JavaScript. Every time you fetch data from a server, upload a file, process a payment, or interact with a cloud service, asynchronous code is involved.
Many beginners struggle with this topic because several concepts—such as the Call Stack, Web APIs, Callback Queue, Microtask Queue, and Event Loop—work together behind the scenes. In this part, we'll build these concepts step by step.
What is Synchronous Programming?
By default, JavaScript executes code one statement at a time in the order it appears.
Example:
console.log("Start"); console.log("Learning JavaScript"); console.log("End");
Output
Start Learning JavaScript End
Each line waits until the previous one has finished.
What is Asynchronous Programming?
Some operations take time to complete, such as:
- Downloading data from a server
- Reading files
- Database queries
- Waiting for user input
- Timers
- Image uploads
- Video streaming
- API requests
Instead of blocking the entire program, JavaScript allows these operations to run asynchronously.
Example
console.log("Start"); setTimeout(() => { console.log("Task Completed"); }, 2000); console.log("End");
Output
Start End Task Completed
JavaScript continues executing other code while waiting for the timer.
Why JavaScript Can Be Asynchronous
JavaScript itself is single-threaded, meaning it executes one task at a time.
However, the browser (or Node.js runtime) provides additional capabilities such as:
- Timers
- Network requests
- DOM events
- File operations
These runtime features make asynchronous programming possible.
JavaScript Execution Model
Understanding how JavaScript executes code is essential.
JavaScript Runtime ┌────────────────────────┐ │ Call Stack │ └──────────┬─────────────┘ │ ▼ ┌────────────────────────┐ │ Web APIs │ │ setTimeout │ │ Fetch API │ │ DOM Events │ └──────────┬─────────────┘ │ ▼ ┌────────────────────────┐ │ Callback Queue │ └──────────┬─────────────┘ │ ▼ ┌────────────────────────┐ │ Microtask Queue │ │ Promises │ └──────────┬─────────────┘ │ ▼ Event Loop │ ▼ Call Stack
Call Stack
The Call Stack keeps track of function execution.
Example
function first() { second(); } function second() { third(); } function third() { console.log("Hello"); } first();
Execution order
Call first() ↓ Call second() ↓ Call third() ↓ Print Hello ↓ Remove third() ↓ Remove second() ↓ Remove first()
The Call Stack follows the Last In, First Out (LIFO) principle.
Web APIs
The browser handles operations such as:
-
setTimeout() -
fetch() - Mouse events
- Keyboard events
- Geolocation
- DOM events
These APIs execute outside the JavaScript engine.
Example
setTimeout(() => { console.log("Done"); },3000);
The timer runs inside the browser's Web API environment, not on the Call Stack.
Callback Queue
When an asynchronous task finishes, its callback is placed in the Callback Queue.
Example
setTimeout(() => { console.log("Hello"); },1000);
Flow
Call Stack ↓ Web API ↓ Callback Queue ↓ Event Loop ↓ Call Stack
The callback executes only when the Call Stack becomes empty.
Event Loop
The Event Loop continuously checks:
- Is the Call Stack empty?
- If yes, move the next callback into the Call Stack.
Without the Event Loop, asynchronous JavaScript would not function correctly.
Microtask Queue
Promise callbacks have higher priority than the Callback Queue.
Example
console.log("Start"); setTimeout(() => { console.log("Timeout"); }, 0); Promise.resolve().then(() => { console.log("Promise"); }); console.log("End");
Output
Start End Promise Timeout
Even with a 0 ms timeout, Promise callbacks execute first because they are placed in the Microtask Queue.
Callback Functions
A callback is a function passed to another function to be executed later.
function greet(name, callback) { console.log(`Hello, ${name}`); callback(); } function goodbye() { console.log("Goodbye!"); } greet("Alice", goodbye);
Output
Hello, Alice Goodbye!
Callback Hell
Deeply nested callbacks quickly become difficult to read.
loginUser(function(user){ getOrders(user,function(orders){ processPayment(orders,function(payment){ sendEmail(payment,function(){ console.log("Completed"); }); }); }); });
Problems:
- Hard to read
- Difficult to debug
- Poor maintainability
- Error handling becomes complex
Promises solve these issues.
Promises
A Promise represents a value that may be available now, later, or never if an error occurs.
Promise states:
Pending ↓ Fulfilled or Rejected
Creating a Promise
const promise = new Promise((resolve, reject) => { const success = true; if(success){ resolve("Operation Successful"); } else{ reject("Operation Failed"); } });
Consuming a Promise
promise .then(result => { console.log(result); }) .catch(error => { console.log(error); });
Output
Operation Successful
Promise Chaining
Promise.resolve(5) .then(number => number * 2) .then(number => number + 10) .then(result => console.log(result));
Output
20
Each .then() receives the value returned by the previous one.
Promise.finally()
finally() runs regardless of whether the Promise succeeds or fails.
fetch("/api/users") .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error)) .finally(() => { console.log("Request finished"); });
async Functions
async makes working with Promises easier.
async function greet(){ return "Hello"; }
An async function always returns a Promise.
greet().then(console.log);
Output
Hello
await
await pauses execution inside an async function until a Promise resolves.
function delay(){ return new Promise(resolve=>{ setTimeout(resolve,2000); }); } async function run(){ console.log("Waiting..."); await delay(); console.log("Completed"); } run();
Output
Waiting... Completed
Fetch API
The Fetch API is the modern way to make HTTP requests.
Basic syntax
fetch(url)
Fetching Data
fetch("https://jsonplaceholder.typicode.com/users") .then(response=>response.json()) .then(data=>{ console.log(data); });
The response is converted to JSON before being used.
Using async/await with Fetch
async function getUsers(){ const response = await fetch( "https://jsonplaceholder.typicode.com/users" ); const users = await response.json(); console.log(users); } getUsers();
This style is cleaner and easier to read than long Promise chains.
Handling Fetch Errors
Always handle errors when working with APIs.
async function loadUsers() { try { const response = await fetch("https://jsonplaceholder.typicode.com/users"); if (!response.ok) { throw new Error(`HTTP Error: ${response.status}`); } const users = await response.json(); console.log(users); } catch (error) { console.error("Failed to load users:", error.message); } }
Understanding JSON
JSON (JavaScript Object Notation) is a lightweight data format used for communication between applications.
JSON
{ "name": "Alice", "age": 25, "city": "London" }
JavaScript Object
const user = { name:"Alice", age:25, city:"London" };
JSON.stringify()
Convert an object into JSON.
const user = { name:"Alice", age:25 }; console.log(JSON.stringify(user));
Output
{"name":"Alice","age":25}
JSON.parse()
Convert JSON back into an object.
const json = '{"name":"Alice","age":25}'; const user = JSON.parse(json); console.log(user);
HTTP Methods
| Method | Purpose |
|---|---|
| GET | Retrieve data |
| POST | Create data |
| PUT | Replace existing data |
| PATCH | Update part of existing data |
| DELETE | Remove data |
Sending POST Requests
fetch("https://jsonplaceholder.typicode.com/posts", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ title: "JavaScript", body: "Modern Guide", userId: 1 }) }) .then(response => response.json()) .then(data => console.log(data));
Promise Utility Methods
Promise.all()
Runs multiple Promises in parallel.
const p1 = Promise.resolve("HTML"); const p2 = Promise.resolve("CSS"); const p3 = Promise.resolve("JavaScript"); Promise.all([p1, p2, p3]) .then(values => console.log(values));
Output
["HTML", "CSS", "JavaScript"]
Promise.allSettled()
Waits for every Promise to finish, regardless of success or failure.
Promise.allSettled([ Promise.resolve("Success"), Promise.reject("Failure") ]).then(results => console.log(results));
Promise.race()
Returns the first settled Promise.
Promise.race([ fetch("/fast-api"), fetch("/slow-api") ]).then(result => console.log(result));
Promise.any()
Returns the first successfully fulfilled Promise and ignores rejected ones until a success occurs.
AbortController
Cancel an ongoing Fetch request.
const controller = new AbortController(); fetch("https://jsonplaceholder.typicode.com/users", { signal: controller.signal }); controller.abort();
Useful for search suggestions and preventing unnecessary network requests.
Practical Project: Random User Viewer
async function loadRandomUser() { try { const response = await fetch("https://randomuser.me/api/"); const data = await response.json(); const user = data.results[0]; console.log(user.name.first, user.name.last); console.log(user.email); } catch (error) { console.error(error); } } loadRandomUser();
Practical Project: Weather App Flow
User enters city ↓ Click Search ↓ Fetch Weather API ↓ Receive JSON ↓ Extract temperature ↓ Update DOM ↓ Display Weather
Common Mistakes
❌ Forgetting to use await before asynchronous operations.
❌ Ignoring response.ok and assuming every request succeeds.
❌ Mixing callbacks, Promises, and async/await unnecessarily in the same code.
❌ Forgetting to return a Promise inside a .then() callback.
❌ Not wrapping await operations in try...catch when errors are possible.
Interview Questions
What is asynchronous programming?
A programming model that allows long-running operations to execute without blocking the main thread.
What is the Event Loop?
The Event Loop monitors the Call Stack and moves completed asynchronous callbacks or microtasks into it when it becomes empty.
Difference between callbacks and Promises?
- Callbacks can lead to deeply nested code.
- Promises provide cleaner chaining and better error handling.
Why use async/await?
It makes asynchronous code easier to read and maintain while still working with Promises under the hood.
What is the Fetch API?
A modern browser API for making HTTP requests and interacting with web services.
Practice Exercises
- Fetch and display users from a public API.
- Build a weather application using a weather API.
- Create a random quote generator.
- Build a GitHub user profile search tool.
- Implement infinite scrolling using asynchronous requests.
- Fetch and display blog posts from a REST API.
- Build a live currency converter using an exchange-rate API.
-
Use
Promise.all()to load multiple resources simultaneously. - Add loading indicators and error messages to an API-driven application.
-
Implement request cancellation with
AbortController.
Congratulations! You've reached the final part of this complete JavaScript guide. In this section, we'll cover production-level JavaScript concepts used in modern applications, including modules, object-oriented programming, error handling, regular expressions, dates, internationalization, performance optimization, testing basics, build tools, deployment, and a collection of real-world projects.
JavaScript Modules (ES Modules)
As applications grow, placing all code in a single file becomes difficult to manage. ES Modules allow you to split your code into reusable files.
Exporting
math.js
export function add(a, b) { return a + b; } export const PI = 3.1415926535;
Importing
app.js
import { add, PI } from "./math.js"; console.log(add(10, 20)); console.log(PI);
Output
30 3.1415926535
Default Export
export default function greet() { console.log("Welcome"); }
Import
import greet from "./greet.js"; greet();
Object-Oriented Programming (OOP)
JavaScript supports object-oriented programming through classes.
Creating a Class
class Student { constructor(name, age) { this.name = name; this.age = age; } introduce() { console.log(`Hi, I'm ${this.name}`); } } const student = new Student("Alice", 22); student.introduce();
Output
Hi, I'm Alice
Inheritance
class Animal { speak() { console.log("Animal Sound"); } } class Dog extends Animal { speak() { console.log("Bark"); } } const dog = new Dog(); dog.speak();
Output
Bark
Getters and Setters
class Employee { constructor(name) { this._name = name; } get name() { return this._name; } set name(value) { this._name = value; } } const emp = new Employee("John"); console.log(emp.name); emp.name = "Alice"; console.log(emp.name);
Static Methods
class Calculator { static add(a, b) { return a + b; } } console.log(Calculator.add(5, 8));
Private Class Fields
Modern JavaScript supports truly private fields.
class BankAccount { #balance = 0; deposit(amount) { this.#balance += amount; } getBalance() { return this.#balance; } } const account = new BankAccount(); account.deposit(500); console.log(account.getBalance());
Error Handling
Applications should never crash unexpectedly.
try...catch
try { let result = 10 / 0; console.log(result); } catch(error) { console.log(error); }
Throwing Errors
function divide(a, b) { if (b === 0) { throw new Error("Division by zero is not allowed."); } return a / b; } try { console.log(divide(10, 0)); } catch(error) { console.log(error.message); }
Custom Error Classes
class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } } throw new ValidationError("Invalid Email");
Regular Expressions (RegExp)
Regular expressions help search and validate text.
Testing Email
const email = "user@example.com"; const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; console.log(pattern.test(email));
Output
true
Extract Numbers
const text = "Order ID: 4589"; const numbers = text.match(/\d+/g); console.log(numbers);
Output
["4589"]
Working with Dates
const today = new Date(); console.log(today);
Formatting Dates
console.log(today.getFullYear()); console.log(today.getMonth() + 1); console.log(today.getDate());
Internationalization API
Display dates and currency according to locale.
const amount = 125000; const formatter = new Intl.NumberFormat("en-IN", { style: "currency", currency: "INR" }); console.log(formatter.format(amount));
Output
₹1,25,000.00
Optional Chaining Review
const user = { profile: { name: "Alice" } }; console.log(user.profile?.name); console.log(user.address?.city);
Nullish Coalescing Review
const username = null; console.log(username ?? "Guest");
Performance Optimization
Modern JavaScript applications should be optimized for speed.
Best practices:
-
Use
constby default. - Minimize unnecessary DOM updates.
- Cache frequently accessed DOM elements.
- Use event delegation.
- Debounce expensive operations.
- Throttle scroll and resize events.
- Lazy-load images and modules.
- Avoid blocking the main thread with heavy computations.
Debouncing
Useful for search boxes.
function debounce(callback, delay) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { callback(...args); }, delay); }; }
Throttling
Useful for scrolling.
function throttle(callback, delay) { let waiting = false; return (...args) => { if (waiting) return; callback(...args); waiting = true; setTimeout(() => { waiting = false; }, delay); }; }
Web Workers
Heavy calculations can block the UI.
Web Workers allow computation in a background thread.
worker.js
self.onmessage = function(event) { const result = event.data * 2; postMessage(result); };
Main file
const worker = new Worker("worker.js"); worker.postMessage(10); worker.onmessage = event => { console.log(event.data); };
Testing Basics
Testing improves software quality.
Popular frameworks:
- Jest
- Vitest
- Mocha
- Cypress (End-to-End)
- Playwright (End-to-End)
Example
function add(a,b){ return a+b; } test("Addition",()=>{ expect(add(5,2)).toBe(7); });
Build Tools
Modern JavaScript projects commonly use:
| Tool | Purpose |
|---|---|
| Vite | Fast frontend development |
| Webpack | Bundling |
| Parcel | Zero-configuration bundler |
| Rollup | Library bundling |
| Babel | JavaScript transpilation |
| ESLint | Code quality |
| Prettier | Code formatting |
| npm | Package management |
| pnpm | Fast package manager |
| Yarn | Alternative package manager |
JavaScript Project Folder Structure
project/ │ ├── index.html ├── package.json ├── src/ │ ├── app.js │ ├── utils.js │ ├── api.js │ ├── components/ │ └── styles/ │ ├── public/ │ ├── assets/ │ └── tests/
Real-World JavaScript Projects
To become job-ready, build practical applications.
Beginner Projects
- Digital Clock
- Calculator
- To-Do List
- Counter App
- Random Quote Generator
- Password Generator
- BMI Calculator
- Stopwatch
- Image Slider
- Notes App
Intermediate Projects
- Weather Dashboard
- Expense Tracker
- Movie Search App
- Currency Converter
- Quiz Application
- Blog CMS Frontend
- Markdown Editor
- Music Player
- Kanban Board
- Chat Application (Frontend)
Advanced Projects
- E-commerce Store
- Video Streaming UI
- Real-Time Chat using WebSockets
- Project Management Dashboard
- AI Chat Interface
- GitHub Repository Explorer
- Collaborative Whiteboard
- Online Code Editor
- File Manager
- Progressive Web App (PWA)
JavaScript Interview Preparation
Frequently asked interview topics:
- Hoisting
- Closures
- Event Loop
- Call Stack
- Promises
- async/await
- Prototype Inheritance
-
thiskeyword - Arrow Functions
- Event Delegation
- DOM Manipulation
- Array Methods
- Modules
- Classes
- REST APIs
- Fetch API
- Local Storage
- Session Storage
- Debouncing
- Throttling
- Memory Leaks
- Garbage Collection
Best Practices for Writing Modern JavaScript
-
Use
constwhenever possible. -
Use
letonly when reassignment is required. -
Prefer
===over==. - Write small, reusable functions.
- Keep functions focused on one responsibility.
- Use descriptive variable names.
- Avoid unnecessary global variables.
-
Handle asynchronous errors with
try...catch. - Validate user input.
- Use modules to organize code.
- Format code consistently with Prettier.
- Lint your code with ESLint.
- Write unit tests for critical logic.
- Avoid mutating data unnecessarily.
- Keep dependencies up to date.
JavaScript Learning Roadmap (2026)
HTML │ ▼ CSS │ ▼ JavaScript Basics │ ▼ ES6+ │ ▼ DOM Manipulation │ ▼ Async JavaScript │ ▼ REST APIs │ ▼ Git & GitHub │ ▼ Node.js │ ▼ React / Vue / Angular │ ▼ TypeScript │ ▼ Testing │ ▼ Build Tools │ ▼ Deployment
Frequently Asked Questions (FAQ)
Is JavaScript worth learning in 2026?
Yes. JavaScript remains one of the most widely used programming languages and is essential for modern web development, powering everything from interactive websites to full-stack applications.
How long does it take to learn JavaScript?
- Basics: 4–6 weeks
- Intermediate concepts: 2–3 months
- Professional proficiency: 6–12 months with consistent practice and project building.
Should I learn JavaScript before React?
Absolutely. React builds upon core JavaScript concepts such as functions, objects, arrays, ES6 modules, asynchronous programming, and DOM interactions.
Is JavaScript enough for backend development?
Yes. Using Node.js, JavaScript can be used to build APIs, authentication systems, real-time applications, and scalable backend services.
What should I learn after JavaScript?
A recommended path is:
- TypeScript
- Node.js & Express
- React (or Vue/Angular)
- Databases (PostgreSQL, MongoDB)
- Git & GitHub
- Docker
- Testing (Jest/Playwright)
- CI/CD and cloud deployment
Conclusion
JavaScript has evolved into one of the most versatile and influential programming languages in software development. From simple browser interactions to enterprise-scale web applications, backend services, mobile apps, desktop software, and AI-powered experiences, JavaScript continues to expand its reach.
The key to mastering JavaScript isn't memorizing syntax—it's consistently building projects that reinforce the concepts you've learned. Start with small applications like a calculator or to-do list, then gradually move toward API-driven apps, dashboards, and full-stack projects. Each project will deepen your understanding of core concepts such as asynchronous programming, modular architecture, and clean code practices.
By completing this guide, you've covered the essential knowledge expected of a modern JavaScript developer in 2026. Continue practicing, stay current with new ECMAScript features, and build a portfolio that demonstrates your skills through real-world applications.
