JavaScript: Logic, Data & Interactivity
JavaScript is the programming language of the web. It makes your pages think, respond, and communicate with the outside world. This module takes you from your first variable to building full API-powered apps.
The Fundamentals — Zero Phase
Variables — Storing Data
Variables are containers for data. In modern JavaScript, we always use const or let — never the old var.
const courseName = "DevPath"; // String
const version = 2026; // Number
const isPublic = true; // Boolean
let score = 0; // Will change
score = score + 10; // Reassignment works with 'let'
Data Types
| Type | Example | Description |
|---|---|---|
| String | "Hello World" | Text wrapped in quotes |
| Number | 42, 3.14 | Integers and decimals |
| Boolean | true / false | On/off, yes/no values |
| Array | ["HTML", "CSS", "JS"] | An ordered list of values |
| Object | { name: "Ali", age: 25 } | A collection of key-value pairs |
| null | null | Intentionally empty value |
| undefined | undefined | Variable declared but not assigned |
Logic & Control — Building Phase
Conditionals — Making Decisions
const score = 85;
if (score >= 90) {
console.log("Grade: A");
} else if (score >= 75) {
console.log("Grade: B");
} else {
console.log("Keep studying!");
}
// Ternary (one-liner if/else)
const label = score >= 75 ? "Passed" : "Failed";
Functions — Reusable Blocks of Code
// Traditional declaration
function greet(name) {
return `Hello, ${name}!`;
}
// Modern Arrow Function (preferred in ES6+)
const greet = (name) => `Hello, ${name}!`;
console.log(greet("Ali")); // "Hello, Ali!"
Loops — Repeating Actions
const skills = ["HTML", "CSS", "JavaScript"];
// for...of loop (recommended for arrays)
for (const skill of skills) {
console.log(`Learning: ${skill}`);
}
// Traditional for loop (use when you need the index)
for (let i = 0; i < skills.length; i++) {
console.log(`${i + 1}. ${skills[i]}`);
}
The DOM & Events — Interactive Phase
The DOM (Document Object Model) is the bridge between JavaScript and your HTML. This is how you make pages interactive.
Selecting Elements
// Select by CSS selector (returns first match)
const title = document.querySelector('h1');
const btn = document.querySelector('#submitBtn');
const cards = document.querySelectorAll('.card'); // Returns NodeList
Manipulating the DOM
const title = document.querySelector('h1');
// Change text
title.textContent = "Welcome to DevPath!";
// Change styles
title.style.color = "#3b82f6";
// Add/remove CSS classes
title.classList.add('highlight');
title.classList.remove('hidden');
title.classList.toggle('active'); // Toggle on/off
Event Listeners — Making Things Happen
const btn = document.querySelector('#myBtn');
btn.addEventListener('click', () => {
alert('Button was clicked!');
});
// Common events: 'click', 'input', 'submit', 'mouseover', 'keydown'
// Event with details
document.querySelector('form').addEventListener('submit', (event) => {
event.preventDefault(); // Stop the page from refreshing
const email = document.querySelector('#email').value;
console.log('Submitted:', email);
});
Advanced Logic — Expert Phase
Array Methods — Transforming Data
In real-world apps you'll work with arrays of data constantly. These three methods are the core of data transformation.
const products = [
{ name: 'Laptop', price: 1200, inStock: true },
{ name: 'Phone', price: 800, inStock: false },
{ name: 'Monitor', price: 350, inStock: true },
];
// MAP — transform each item into something new
const names = products.map(p => p.name);
// → ["Laptop", "Phone", "Monitor"]
// FILTER — extract only items matching a condition
const available = products.filter(p => p.inStock);
// → [{Laptop}, {Monitor}]
// REDUCE — boil the array down to a single value
const total = products.reduce((sum, p) => sum + p.price, 0);
// → 2350
Closures & Scope
// A closure "remembers" its surrounding variables
function createCounter() {
let count = 0; // Private — cannot be accessed from outside
return {
increment: () => ++count,
decrement: () => --count,
value: () => count,
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.decrement(); // 1
console.log(counter.value()); // 1
A: JavaScript moves function and
var declarations to the top of their scope before execution. let and const are hoisted but NOT initialized — accessing them before declaration causes a ReferenceError (the "Temporal Dead Zone").
Async/Await & APIs — Pro Phase
Modern applications are network-heavy. async/await lets you fetch real data from external services without freezing the browser.
const fetchUser = async (userId) => {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
// Always check if the response was successful
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json(); // Parse JSON
return data;
} catch (error) {
console.error('Fetch failed:', error.message);
showErrorUI(); // Always handle errors gracefully
} finally {
hideLoadingSpinner(); // Always runs, even on error
}
};
fetchUser(42);
Destructuring & Spread (ES6+)
// Object Destructuring
const { name, price } = product;
// Array Destructuring
const [first, second] = skills;
// Spread — copy and extend objects/arrays
const updatedProduct = { ...product, price: 999 };
// Optional Chaining — avoid "cannot read property" errors
const city = user?.address?.city ?? 'City not provided';
?.) when accessing nested object properties from API responses. APIs frequently return inconsistent data — this prevents your entire app from crashing on a missing field.String & Object Methods
You'll manipulate strings and objects constantly. These methods are used daily by every JavaScript developer.
Essential String Methods
const text = " Hello, DevPath World! ";
text.trim() // "Hello, DevPath World!" (removes whitespace)
text.toLowerCase() // " hello, devpath world! "
text.toUpperCase() // " HELLO, DEVPATH WORLD! "
text.includes('DevPath') // true
text.startsWith(' Hello') // true
text.indexOf('World') // 17
text.slice(8, 15) // "DevPath" (extract substring)
text.replace('World', 'JS') // " Hello, DevPath JS! "
text.split(', ') // [" Hello", "DevPath World! "] (string → array)
// Template Literals — embed expressions inside strings
const name = 'Ali';
const age = 25;
const bio = `${name} is ${age} years old and starts in ${2026 - age}.`;
// "Ali is 25 years old and starts in 2001."
// Multi-line strings
const html = `
<div class="card">
<h2>${name}</h2>
<p>Age: ${age}</p>
</div>
`;
Essential Object Methods
const user = { name: 'Ali', role: 'developer', age: 25 };
// Get all keys
Object.keys(user); // ["name", "role", "age"]
// Get all values
Object.values(user); // ["Ali", "developer", 25]
// Get key-value pairs
Object.entries(user); // [["name","Ali"], ["role","developer"], ["age",25]]
// Loop through an object
for (const [key, value] of Object.entries(user)) {
console.log(`${key}: ${value}`);
}
// Merge objects
const defaults = { theme: 'dark', lang: 'en' };
const prefs = { theme: 'light' };
const config = { ...defaults, ...prefs };
// { theme: 'light', lang: 'en' } ← prefs overrides defaults
// Check if key exists
'name' in user; // true
user.hasOwnProperty('email'); // false
LocalStorage & Timers
LocalStorage — Persisting Data in the Browser
localStorage lets you save data that survives page refreshes and browser restarts. It stores everything as strings.
// Save a simple value
localStorage.setItem('username', 'Ali');
// Retrieve it
const name = localStorage.getItem('username'); // "Ali"
// Remove one item
localStorage.removeItem('username');
// Clear everything
localStorage.clear();
// Save complex data (objects/arrays) — must convert to JSON
const tasks = [
{ text: 'Learn JS', done: false },
{ text: 'Build project', done: true },
];
localStorage.setItem('tasks', JSON.stringify(tasks));
// Retrieve and parse back into an array
const saved = JSON.parse(localStorage.getItem('tasks') || '[]');
Security: Never store passwords or tokens in localStorage — it's accessible by any script on the page (XSS vulnerable).
Type: Everything is stored as a string. Always use
JSON.stringify/JSON.parse for objects.
setTimeout & setInterval
// Run once after a delay (in milliseconds)
setTimeout(() => {
console.log('This runs after 2 seconds');
}, 2000);
// Run repeatedly at an interval
const timerId = setInterval(() => {
console.log('This runs every second');
}, 1000);
// Stop the interval
clearInterval(timerId);
// Real-world: auto-save form data every 30 seconds
setInterval(() => {
const formData = document.querySelector('#editor').value;
localStorage.setItem('draft', formData);
console.log('Draft auto-saved');
}, 30000);
// Debounce — wait until user stops typing
let debounceTimer;
const searchInput = document.querySelector('#search');
searchInput.addEventListener('input', (e) => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
performSearch(e.target.value);
}, 300); // Only fires 300ms after user stops typing
});
Error Handling
Professional applications never crash silently. You must anticipate failures and handle them gracefully.
try {
// Code that might fail
const data = JSON.parse(badJsonString);
} catch (error) {
// Handle the error
console.error('Parse failed:', error.message);
showUserFriendlyError('Invalid data format');
} finally {
// Always runs — cleanup code
hideLoadingSpinner();
}
Error Types
| Error Type | When It Happens | Example |
|---|---|---|
ReferenceError | Using a variable that doesn't exist | console.log(x) when x is not declared |
TypeError | Using a value the wrong way | null.toString() |
SyntaxError | Malformed code | Missing bracket or quote |
RangeError | Number out of valid range | new Array(-1) |
Throwing Custom Errors
const validateAge = (age) => {
if (typeof age !== 'number') {
throw new TypeError('Age must be a number');
}
if (age < 0 || age > 150) {
throw new RangeError('Age must be between 0 and 150');
}
return true;
};
try {
validateAge('twenty');
} catch (e) {
console.error(`${e.name}: ${e.message}`);
// "TypeError: Age must be a number"
}
ES6 Modules
As your projects grow, you split code into separate files. ES6 Modules let you export from one file and import into another.
// Named exports — you can have many per file
export const formatPrice = (cents) => `$${(cents / 100).toFixed(2)}`;
export const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
// Default export — one per file (the "main" thing)
const API_URL = 'https://api.example.com';
export default API_URL;
// Import named exports (use curly braces)
import { formatPrice, capitalize } from './utils.js';
// Import default export (no braces, any name you want)
import API_URL from './utils.js';
// Import everything as a namespace
import * as Utils from './utils.js';
Utils.formatPrice(1999); // "$19.99"
<!-- Add type="module" to use import/export -->
<script type="module" src="app.js"></script>
import/export is a prerequisite for learning any framework. Start organizing your vanilla JS projects into modules now.
The JavaScript Pro Roadmap
| Level | Focus | Key Concept to Master |
|---|---|---|
| Beginner | Basics | Variables, Data Types & Operators |
| Intermediate | Logic | Functions, Loops & DOM Events |
| Advanced | Efficiency | Array Methods & Closures |
| Pro | Real Apps | Async/Await, APIs & Error Handling |