This roadmap is for restarting/revising full-stack development from JavaScript fundamentals to backend development.
Goal:
Build strong JavaScript logic, understand frontend DOM basics, learn async/API calls, then start backend development with Node.js and Express.
- Phase 1: JavaScript Fundamentals
- Phase 1 Extras
- Important Array Methods
- Phase 2: DOM Manipulation
- Todo App with DOM
- localStorage
- ES Modules
- Async JavaScript
- Fetch API
- Error Handling
The goal of Phase 1 is to become comfortable writing basic JavaScript logic without React, Node.js, or any framework.
- Variables:
let,const - Data types:
- string
- number
- boolean
- null
- undefined
- array
- object
- Operators:
+,-,*,/,%===,!==,>,<,>=,<=&&,||,!
- Conditions:
ifelse ifelseswitch
- Loops:
forwhilefor...of
- Functions:
- normal functions
- arrow functions
- parameters
- return values
- Arrays
- Objects
const name = "Abhishek";
const age = 22;
const city = "Ranchi";
console.log(name);
console.log(age);
console.log(city);const age = 18;
if (age >= 18) {
console.log("You can vote");
} else {
console.log("You cannot vote");
}for (let i = 1; i <= 5; i++) {
console.log(i);
}function add(a, b) {
return a + b;
}
const result = add(10, 20);
console.log(result);Build these small console programs:
- Calculator
- Even/Odd checker
- Student marks calculator
- Expense tracker
- Todo list in console
These are small but very important for React and backend development.
const name = "Abhishek";
const skill = "JavaScript";
console.log(`My name is ${name} and I am learning ${skill}`);const user = {
name: "Abhishek",
age: 22,
skill: "JavaScript",
};
const { name, skill } = user;
console.log(name);
console.log(skill);const skills = ["HTML", "CSS", "JavaScript"];
const [firstSkill, secondSkill] = skills;
console.log(firstSkill);
console.log(secondSkill);function addNumbers(...numbers) {
return numbers.reduce((total, number) => total + number, 0);
}
console.log(addNumbers(10, 20, 30));const user = {
name: "Abhishek",
profile: {
image: "avatar.png",
},
};
console.log(user.profile?.image);
console.log(user.address?.city);Falsy values:
false
0
""
null
undefined
NaNExample:
const name = "";
if (name) {
console.log("Name exists");
} else {
console.log("Name is missing");
}const age = 18;
const message = age >= 18 ? "Adult" : "Minor";
console.log(message);const isLoggedIn = true;
isLoggedIn && console.log("Show dashboard");const text = " JavaScript is awesome ";
console.log(text.toLowerCase());
console.log(text.toUpperCase());
console.log(text.includes("Script"));
console.log(text.trim());
console.log(text.split(" "));const user = {
name: "Abhishek",
skill: "JavaScript",
city: "Ranchi",
};
console.log(Object.keys(user));
console.log(Object.values(user));
console.log(Object.entries(user));These are must-know for React, backend logic, and full-stack development.
map -> transform every item
filter -> keep only matching items
reduce -> convert array into single value
slice -> copy part of array
splice -> change original array
find -> get first matching item
sort -> arrange items
includes -> check if value exists
push/pop -> add/remove from end
... -> copy/merge arrays or objectsUse map when you want to transform every item.
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((number) => {
return number * 2;
});
console.log(doubled);Use filter when you want to keep only matching items.
const numbers = [1, 2, 3, 4, 5, 6];
const evenNumbers = numbers.filter((number) => {
return number % 2 === 0;
});
console.log(evenNumbers);Use reduce when you want one final value.
const numbers = [10, 20, 30];
const total = numbers.reduce((acc, number) => {
return acc + number;
}, 0);
console.log(total);slice copies part of an array and does not change the original array.
const numbers = [10, 20, 30, 40, 50];
const result = numbers.slice(1, 4);
console.log(result);splice changes the original array.
const fruits = ["apple", "banana", "mango", "orange"];
fruits.splice(1, 2);
console.log(fruits);find returns the first matching item.
const users = [
{ id: 1, name: "Abhishek" },
{ id: 2, name: "Rahul" },
{ id: 3, name: "Aman" },
];
const user = users.find((user) => {
return user.id === 2;
});
console.log(user);sort arranges items and changes the original array.
const numbers = [100, 5, 20, 1];
numbers.sort((a, b) => {
return a - b;
});
console.log(numbers);const skills = ["HTML", "CSS", "JavaScript"];
console.log(skills.includes("JavaScript"));
console.log(skills.includes("React"));const fruits = ["apple", "banana"];
fruits.push("mango");
fruits.pop();
console.log(fruits);const frontend = ["HTML", "CSS"];
const backend = ["Node", "Express"];
const fullStack = [...frontend, ...backend];
console.log(fullStack);Methods that usually do not change original array:
map
filter
reduce
slice
find
includes
spread operatorMethods that change original array:
push
pop
splice
sortDOM means Document Object Model.
Simple meaning:
Browser converts HTML into a JavaScript-controllable object.
getElementByIdquerySelectorquerySelectorAll- changing text
- changing HTML
- changing styles
- adding/removing classes
- events
- form handling
- creating elements
- removing elements
<h1 id="title">Hello</h1>const title = document.getElementById("title");
console.log(title);title.textContent = "Hello JavaScript";const box = document.getElementById("box");
box.innerHTML = "<h2>Hello from JS</h2>";title.style.color = "red";
title.style.backgroundColor = "black";
title.style.fontSize = "40px";title.classList.add("active");
title.classList.remove("active");
title.classList.toggle("active");<button id="btn">Click me</button>const btn = document.getElementById("btn");
btn.addEventListener("click", () => {
console.log("Button clicked");
});<input id="nameInput" type="text" />
<p id="output"></p>const input = document.getElementById("nameInput");
const output = document.getElementById("output");
input.addEventListener("input", () => {
output.textContent = input.value;
});<form id="form">
<input id="nameInput" type="text" placeholder="Enter name" />
<button type="submit">Submit</button>
</form>
<p id="result"></p>const form = document.getElementById("form");
const input = document.getElementById("nameInput");
const result = document.getElementById("result");
form.addEventListener("submit", (event) => {
event.preventDefault();
result.textContent = `Hello ${input.value}`;
});const list = document.getElementById("list");
const li = document.createElement("li");
li.textContent = "Learn JavaScript";
list.appendChild(li);const item = document.getElementById("item");
item.remove();- Counter app
- Character counter
- Password show/hide
- Theme toggle
- Todo app
This project combines arrays, objects, functions, DOM, events, forms, and rendering.
- Add todo
- Show todos
- Delete todo
- Mark todo as completed
<!DOCTYPE html>
<html lang="en">
<head>
<title>Todo App</title>
</head>
<body>
<h1>Todo App</h1>
<form id="todoForm">
<input id="todoInput" type="text" placeholder="Enter todo" />
<button type="submit">Add Todo</button>
</form>
<ul id="todoList"></ul>
<script src="script.js"></script>
</body>
</html>const todoForm = document.getElementById("todoForm");
const todoInput = document.getElementById("todoInput");
const todoList = document.getElementById("todoList");
let todos = [];
todoForm.addEventListener("submit", function (event) {
event.preventDefault();
const todoText = todoInput.value.trim();
if (todoText === "") {
alert("Please enter a todo");
return;
}
const newTodo = {
id: Date.now(),
text: todoText,
completed: false,
};
todos.push(newTodo);
todoInput.value = "";
renderTodos();
});
function renderTodos() {
todoList.innerHTML = "";
todos.forEach(function (todo) {
const li = document.createElement("li");
const span = document.createElement("span");
span.textContent = todo.text;
if (todo.completed) {
span.style.textDecoration = "line-through";
}
span.addEventListener("click", function () {
todo.completed = !todo.completed;
renderTodos();
});
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "Delete";
deleteBtn.addEventListener("click", function () {
todos = todos.filter(function (item) {
return item.id !== todo.id;
});
renderTodos();
});
li.appendChild(span);
li.appendChild(deleteBtn);
todoList.appendChild(li);
});
}- Show total todos count
- Show completed todos count
- Add clear all button
- Add edit todo feature
- Add localStorage
localStorage stores data inside the browser.
Important:
localStorage only stores stringsSo for arrays and objects, use:
JSON.stringify();
JSON.parse();localStorage.setItem("name", "Abhishek");const name = localStorage.getItem("name");
console.log(name);localStorage.removeItem("name");localStorage.clear();const user = {
name: "Abhishek",
skill: "JavaScript",
};
localStorage.setItem("user", JSON.stringify(user));const storedUser = localStorage.getItem("user");
const user = JSON.parse(storedUser);
console.log(user);Change:
let todos = [];to:
let todos = JSON.parse(localStorage.getItem("todos")) || [];Add save function:
function saveTodos() {
localStorage.setItem("todos", JSON.stringify(todos));
}Call this whenever todos change:
saveTodos();
renderTodos();<button id="themeBtn">Toggle Theme</button>.dark {
background-color: black;
color: white;
}const themeBtn = document.getElementById("themeBtn");
const savedTheme = localStorage.getItem("theme");
if (savedTheme === "dark") {
document.body.classList.add("dark");
}
themeBtn.addEventListener("click", function () {
document.body.classList.toggle("dark");
if (document.body.classList.contains("dark")) {
localStorage.setItem("theme", "dark");
} else {
localStorage.setItem("theme", "light");
}
});Modules help us split code into multiple files.
Instead of one large file:
script.jsUse:
main.js
math.js
users.js
api.jsConnect files using:
import
export<script type="module" src="main.js"></script>export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}import { add, multiply } from "./math.js";
console.log(add(10, 20));
console.log(multiply(5, 3));function calculator(a, b) {
return a + b;
}
export default calculator;import calculator from "./calculator.js";
console.log(calculator(10, 5));Named export:
export function add(a, b) {
return a + b;
}Import with curly braces:
import { add } from "./math.js";Default export:
export default function add(a, b) {
return a + b;
}Import without curly braces:
import add from "./math.js";import * as math from "./math.js";
console.log(math.add(10, 20));
console.log(math.multiply(5, 3));import { add as sum } from "./math.js";
console.log(sum(10, 20));Async JavaScript helps us handle delayed work like API calls, timers, file reading, and database calls.
Learn in this order:
callbacks
promises
async/await
fetch/API callsconsole.log("One");
console.log("Two");
console.log("Three");Output:
One
Two
Threeconsole.log("One");
setTimeout(() => {
console.log("Two");
}, 2000);
console.log("Three");Output:
One
Three
TwoA callback is a function passed into another function.
function greet(name, callback) {
console.log("Hello " + name);
callback();
}
function sayBye() {
console.log("Bye");
}
greet("Abhishek", sayBye);function fetchUser(callback) {
setTimeout(() => {
const user = {
name: "Abhishek",
age: 22,
};
callback(user);
}, 2000);
}
fetchUser((user) => {
console.log(user);
});A Promise gives a future result: success or failure.
States:
pending
fulfilled
rejectedExample:
const promise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve("Data received");
} else {
reject("Something went wrong");
}
});
promise
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
});function fetchUser() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const user = {
id: 1,
name: "Abhishek",
};
resolve(user);
}, 2000);
});
}
fetchUser()
.then((user) => {
console.log(user);
})
.catch((error) => {
console.log(error);
});function getUser() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: 1, name: "Abhishek" });
}, 1000);
});
}
function getPosts(userId) {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{ id: 101, title: "Post 1", userId },
{ id: 102, title: "Post 2", userId },
]);
}, 1000);
});
}
getUser()
.then((user) => {
console.log("User:", user);
return getPosts(user.id);
})
.then((posts) => {
console.log("Posts:", posts);
})
.catch((error) => {
console.log(error);
});async/await is a cleaner way to write promises.
function fetchUser() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id: 1, name: "Abhishek" });
}, 2000);
});
}
async function main() {
const user = await fetchUser();
console.log(user);
}
main();function loginUser(email, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (email === "test@gmail.com" && password === "123456") {
resolve("Login successful");
} else {
reject("Invalid credentials");
}
}, 1000);
});
}
async function handleLogin() {
try {
const result = await loginUser("test@gmail.com", "wrong");
console.log(result);
} catch (error) {
console.log("Error:", error);
}
}
handleLogin();Callback:
fetchUser((user) => {
console.log(user);
});Promise:
fetchUser()
.then((user) => {
console.log(user);
})
.catch((error) => {
console.log(error);
});Async/Await:
try {
const user = await fetchUser();
console.log(user);
} catch (error) {
console.log(error);
}fetch() is used to call an API.
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => {
return response.json();
})
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log("Error:", error);
});async function getUsers() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
const data = await response.json();
console.log(data);
} catch (error) {
console.log("Error:", error);
}
}
getUsers();async function getUsers() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
if (!response.ok) {
throw new Error("Failed to fetch users");
}
const data = await response.json();
console.log(data);
} catch (error) {
console.log("Error:", error.message);
}
}
getUsers();GET means read data.
async function getPosts() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
if (!response.ok) {
throw new Error("Failed to fetch posts");
}
const posts = await response.json();
console.log(posts);
} catch (error) {
console.log(error.message);
}
}
getPosts();POST means send/create data.
async function createPost() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Learning Fetch",
body: "Fetch is important for full stack",
userId: 1,
}),
});
if (!response.ok) {
throw new Error("Failed to create post");
}
const data = await response.json();
console.log(data);
} catch (error) {
console.log("Error:", error.message);
}
}
createPost();GET -> read data
POST -> create data
PUT -> replace/update full data
PATCH -> update partial data
DELETE -> delete dataGET /api/users -> get all users
GET /api/users/1 -> get one user
POST /api/users -> create user
PATCH /api/users/1 -> update user
DELETE /api/users/1 -> delete userError handling prevents your app from crashing or behaving badly.
try {
console.log("Start");
const result = 10 / 2;
console.log(result);
} catch (error) {
console.log("Something went wrong");
}try {
console.log(user.name);
} catch (error) {
console.log("Error:", error.message);
}function divide(a, b) {
if (b === 0) {
throw new Error("Cannot divide by zero");
}
return a / b;
}
try {
const result = divide(10, 0);
console.log(result);
} catch (error) {
console.log(error.message);
}function login(email, password) {
if (!email) {
throw new Error("Email is required");
}
if (!password) {
throw new Error("Password is required");
}
return "Login successful";
}
try {
const result = login("", "123456");
console.log(result);
} catch (error) {
console.log(error.message);
}try {
console.log("Trying...");
throw new Error("Something failed");
} catch (error) {
console.log("Error:", error.message);
} finally {
console.log("Cleanup done");
}async function getUsers() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
if (!response.ok) {
throw new Error("Failed to fetch users");
}
const users = await response.json();
console.log(users);
} catch (error) {
console.log("Error:", error.message);
}
}
getUsers();