The Ultimate JavaScript Tutorial: From Beginner to
Intermediate
Welcome! This hands-on guide takes you from zero to intermediate-level JavaScript, one small step at a
time. Every chapter explains the why as well as the how, and ends with short practice challenges to cement
your learning.
Part 1: The Absolute Beginner's Guide to JavaScript
Chapter 1: Introduction to JavaScript
What is JavaScript and why is it essential for web development?
JavaScript (JS) is the programming language of the web. It lets you make pages interactive: handle clicks,
validate forms, fetch data, animate UI, and much more. Alongside HTML (structure) and CSS (styling),
JavaScript forms the third pillar of web development.
A brief history of JavaScript
• 1995: Created by Brendan Eich at Netscape in ~10 days, first called Mocha, then LiveScript, finally
JavaScript.
• 1997: Standardized as ECMAScript (ES) so all browsers could agree on its features.
• 2015 (ES6/ES2015): A huge update added let , const , classes, arrow functions, template literals,
modules, etc.
• Since then, JS evolves yearly with smaller, steady improvements.
Setting up your development environment
• Code editor: VS Code (popular), WebStorm (paid), or any editor you like.
• Browser: Modern browsers (Chrome, Firefox, Edge, Safari) with built-in Developer Tools.
• [Link] (optional): Lets you run JS outside the browser and use npm packages.
How to run JavaScript
1) In an HTML file
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello JS</title>
</head>
1
<body>
<h1>Check the console!</h1>
<!-- Inline script -->
<script>
[Link]('Hello, World! (inline)');
</script>
<!-- External script -->
<script src="[Link]" defer></script>
</body>
</html>
Tip: Use defer so the script runs after HTML is parsed (preventing blocking and ensuring
elements exist).
2) In the browser console - Open DevTools (F12 or Ctrl/Cmd+Shift+I) → Console tab → type
[Link]('Hello'); and press Enter.
Your first "Hello, World!"
[Link]('Hello, World!');
Practice 1. Create an HTML page and log two messages: one inline, one from an external [Link] . 2.
Open the console and try basic math, e.g., 2 + 2 and [Link](16) .
Chapter 2: JavaScript Fundamentals
Variables and scope: var , let , const
• let : block-scoped, re-assignable.
• const : block-scoped, not re-assignable (but object/array contents can change).
• var : function-scoped, hoisted in a way that often surprises—avoid in modern code.
let count = 1;
count = 2; // ok
const pi = 3.14159;
// pi = 3; // ❌ TypeError: Assignment to constant variable
if (true) {
let inside = 'I exist only in this block';
2
}
// [Link](inside); // ❌ ReferenceError
Data Types - Primitives: string , number , boolean , null , undefined , symbol , bigint -
Objects: everything else: plain objects, arrays, functions, dates, etc.
const s = 'text'; // string
const n = 42; // number (integers & floats)
const b = true; // boolean
const x = null; // intentional "no value"
let u; // undefined (declared, not assigned)
const sym = Symbol('id'); // unique identifier
const big = 123n; // BigInt for very large integers
const arr = [1, 2, 3];
const obj = { name: 'Ada', age: 28 };
Operators - Arithmetic: + - * / % ** - Assignment: = += -= *= /= %= - Comparison: === !== >
>= < <= (use strict equality === ) - Logical: && || ! - Ternary: condition ? A : B
const age = 20;
const canVote = age >= 18 ? 'yes' : 'no';
Type coercion & conversion
JavaScript can coerce types:
'5' + 3; // '53' (string concatenation)
'5' - 3; // 2 (minus forces numbers)
Boolean(''); // false
Number('42'); // 42
parseInt('101', 2); // 5 (binary)
Prefer explicit conversion ( Number , String , Boolean ) and strict equality ( === ).
Practice 1. Declare variables with let / const . Try to reassign a const and observe the error. 2.
Convert user input '123' to a number and add 7. 3. Write a ternary that outputs 'adult' or 'minor'
based on age .
Chapter 3: Control Flow and Logic
Conditionals
3
const score = 85;
if (score >= 90) {
[Link]('A');
} else if (score >= 80) {
[Link]('B');
} else {
[Link]('C or below');
}
const role = 'admin';
switch (role) {
case 'admin':
[Link]('Full access');
break;
case 'editor':
[Link]('Edit access');
break;
default:
[Link]('Read-only');
}
Loops
for (let i = 0; i < 3; i++) [Link](i);
let j = 0;
while (j < 3) { [Link](j); j++; }
do { [Link]('once'); } while (false);
const nums = [10, 20, 30];
for (const value of nums) [Link](value); // for...of → values
const person = { name: 'Lin', city: 'Taipei' };
for (const key in person) [Link](key, person[key]); // for...in → keys
Truthy & Falsy - Falsy values: false, 0, -0, 0n, '', null, undefined, NaN - Everything else is
truthy.
Practice 1. Write a function that prints “Fizz” for multiples of 3, “Buzz” for 5, “FizzBuzz” for both, else the
number (1..30). 2. Loop over an object and print key: value pairs.
4
Chapter 4: Functions
Defining & calling
function greet(name) {
return `Hello, ${name}!`;
}
[Link](greet('Ava'));
Parameters, arguments & defaults
function multiply(a, b = 1) { // default value
return a * b;
}
Return values - Functions return undefined if you don’t return explicitly.
Declarations vs. expressions
// Declaration (hoisted)
function area(r) { return [Link] * r * r; }
// Expression (not hoisted)
const perimeter = function (r) { return 2 * [Link] * r; };
Arrow functions
const double = x => x * 2; // concise, implicit return
const sum = (a, b) => { return a + b; }; // block body → need return
// Arrow functions don’t have their own `this`; great for callbacks
[1, 2, 3].map(n => n * 2);
Practice 1. Write an arrow function isEven(n) that returns true for even numbers. 2. Convert a
function declaration to an expression and to an arrow function.
Chapter 5: Data Structures
Arrays
5
const fruits = ['apple', 'banana'];
[Link]('cherry'); // add to end
[Link](); // remove from end
[Link]('kiwi'); // add to start
[Link](); // remove from start
const copy = [Link](); // non-destructive copy
[Link](1, 0, 'mango'); // insert at index 1
// Iteration
[Link](f => [Link](f));
// Transform/Filter/Accumulate
const lengths = [Link](f => [Link]);
const longOnes = [Link](f => [Link] > 5);
const totalLetters = [Link]((acc, f) => acc + [Link], 0);
Objects & this
const user = {
name: 'Sam',
greet() {
[Link](`Hi, I'm ${[Link]}`);
},
};
[Link](); // `this` refers to `user` when called as a method
// Access
[Link]([Link]); // dot
[Link](user['name']); // bracket (allows dynamic keys)
Practice 1. Given const nums = [3, 6, 9, 12] , create a new array of halves using map . 2. From an
array of words, filter those containing the letter a . 3. Create an object counter with methods inc ,
dec , and value .
Chapter 6: Interacting with the Web – The DOM
What is the DOM?
The Document Object Model is a tree-like representation of your HTML that JavaScript can read and
change.
Selecting elements
6
const title = [Link]('title');
const firstButton = [Link]('button');
const allItems = [Link]('.item'); // NodeList
Manipulating elements
[Link] = 'New Title'; // safer than innerHTML for plain text
[Link]('aria-pressed', 'true');
[Link]('primary');
[Link] = '0.5rem';
Creating & deleting
const li = [Link]('li');
[Link] = 'New item';
[Link]('ul').appendChild(li);
[Link](); // delete element
Handling events
const form = [Link]('form');
[Link]('submit', (e) => {
[Link](); // stop page reload
const input = [Link]('#todo');
[Link]('Submitted:', [Link]);
});
Practice 1. Select a paragraph and change its text on a button click. 2. Create a new list item from an input
field and append it to a list.
Project 1: Simple To‑Do List App (Part 1 concepts)
Goal: Add tasks, mark them done, delete them.
HTML
<!doctype html>
<html>
7
<head>
<meta charset="utf-8" />
<title>To‑Do</title>
<style>
body { font-family: system-ui; max-width: 600px; margin: 2rem auto; }
[Link] { text-decoration: line-through; opacity: 0.6; }
button { margin-left: 0.5rem; }
</style>
</head>
<body>
<h1>To‑Do</h1>
<form id="form">
<input id="todo" placeholder="Add a task" required />
<button>Add</button>
</form>
<ul id="list"></ul>
<script src="[Link]" defer></script>
</body>
</html>
[Link]
const form = [Link]('form');
const input = [Link]('todo');
const list = [Link]('list');
[Link]('submit', (e) => {
[Link]();
const text = [Link]();
if (!text) return;
const li = [Link]('li');
const toggleBtn = [Link]('button');
const removeBtn = [Link]('button');
[Link] = 'Done';
[Link] = '✕';
[Link] = text;
[Link](toggleBtn, removeBtn);
[Link](li);
[Link] = '';
[Link]();
8
[Link]('click', () => {
[Link]('done');
});
[Link]('click', () => {
[Link]();
});
});
Stretch ideas: Save to localStorage , add filters (All/Active/Done).
Part 2: The Intermediate Developer's Path
Chapter 7: Modern JavaScript (ES6+)
Template literals
const name = 'Kai';
[Link](`Hello, ${name}! Today is ${new Date().toDateString()}.`);
Destructuring
const point = { x: 10, y: 20 };
const { x, y } = point; // object destructuring
const rgb = [255, 128, 64];
const [r, g, b] = rgb; // array destructuring
Spread & Rest
const a1 = [1, 2], a2 = [3, 4];
const merged = [...a1, ...a2]; // spread arrays
const user = { name: 'Jo', age: 30 };
const user2 = { ...user, city: 'Seoul' }; // spread objects (shallow)
function sum(...nums) { // rest parameters → array
return [Link]((acc, n) => acc + n, 0);
}
9
Default parameters
function greet(name = 'friend') {
return `Hi, ${name}!`;
}
Block scope ( let , const ) deep dive
for (let i = 0; i < 3; i++) {
setTimeout(() => [Link](i), 0); // 0, 1, 2 because `i` is block-scoped
}
Practice 1. Combine two arrays with spread, then remove duplicates using a Set . 2. Write maxOf that
accepts any number of arguments via rest parameters.
Chapter 8: Asynchronous JavaScript
Sync vs. Async - Synchronous: operations happen in order; one task at a time. - Asynchronous: a task starts,
and when it finishes later, your code handles the result (without blocking the main thread).
Callbacks & “callback hell”
setTimeout(() => {
[Link]('Step 1');
setTimeout(() => {
[Link]('Step 2');
setTimeout(() => {
[Link]('Step 3');
}, 500);
}, 500);
}, 500);
Promises
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
delay(500)
.then(() => [Link]('Done after 500ms'))
.catch(err => [Link]('Error:', err))
.finally(() => [Link]('Always runs'));
10
async/await
async function steps() {
try {
await delay(500);
[Link]('Step A');
await delay(500);
[Link]('Step B');
} catch (err) {
[Link](err);
}
}
steps();
Fetching data with fetch
async function getJoke() {
const res = await fetch('[Link]
if (![Link]) throw new Error('Network response was not ok');
const data = await [Link]();
[Link]([Link]);
}
getJoke();
[Link] (run in parallel)
const urls = [
'[Link]
'[Link]
];
async function fetchAll() {
const responses = await [Link]([Link](u => fetch(u)));
const payloads = await [Link]([Link](r => [Link]()));
[Link](payloads);
}
Practice 1. Write a wait(ms) function that returns a Promise. Use await to log after 1s. 2. Use
[Link] to fetch two public APIs and log both results.
11
Chapter 9: Object‑Oriented Programming (OOP) in JavaScript
Prototypes & prototypal inheritance
const animal = {
speak() { [Link]('generic sound'); }
};
const dog = [Link](animal);
[Link] = function () { [Link]('woof'); };
[Link](); // 'woof'
[Link](dog) === animal; // true
Constructor functions
function Person(name) {
[Link] = name;
}
[Link] = function () {
[Link]('Hi, I am ' + [Link]);
};
const p = new Person('Mina');
[Link]();
ES6 Classes
class Person {
constructor(name) {
[Link] = name;
}
greet() { [Link](`Hi, I am ${[Link]}`); }
}
class Student extends Person {
constructor(name, major) {
super(name); // call parent constructor
[Link] = major;
}
study() { [Link](`${[Link]} studies ${[Link]}`); }
}
12
const s = new Student('Noah', 'CS');
[Link]();
[Link]();
Getters & Setters
class Rectangle {
constructor(w, h) { this.w = w; this.h = h; }
get area() { return this.w * this.h; }
set width(value) { this.w = value; }
}
const r = new Rectangle(4, 5);
[Link]([Link]); // 20
[Link] = 10;
[Link]([Link]); // 50
Practice 1. Create a BankAccount class with deposit , withdraw , and a getter balance . 2.
Implement Car → ElectricCar with extends and an extra method charge() .
Chapter 10: Functional Programming Concepts
Pure functions & side effects - Pure: output depends only on inputs; no external state changes. - Avoid
mutating inputs—return new values instead.
Immutability
const arr = [1, 2, 3];
const arr2 = [Link](4); // arr unchanged
const user = { name: 'A', points: 0 };
const updated = { ...user, points: [Link] + 10 };
Higher‑Order Functions
const numbers = [1, 2, 3, 4, 5];
const evens = [Link](n => n % 2 === 0);
const squares = [Link](n => n * n);
const sum = [Link]((acc, n) => acc + n, 0);
13
Closures
function makeCounter() {
let count = 0; // private via closure
return function () {
count++;
return count;
};
}
const next = makeCounter();
[Link](next()); // 1
[Link](next()); // 2
Practical closure uses: memoization, function factories, encapsulating module state, debouncing.
Practice 1. Write a once(fn) that runs fn only the first time it’s called. 2. Implement a debounce(fn,
delay) that delays calling fn until no calls happen for delay ms.
Chapter 11: Modules and Tooling
ES Modules in the browser
[Link]
<script type="module" src="[Link]"></script>
[Link]
export function add(a, b) { return a + b; }
export const PI = 3.14159;
[Link]
import { add, PI } from './[Link]';
[Link](add(2, 3), PI);
Node & npm (Node Package Manager)
14
# install [Link] first, then in a project folder:
npm init -y # create [Link]
npm install dayjs # example dependency
node -e "[Link](require('dayjs')().format())"
Code quality tools
npm install -D eslint prettier
npx eslint --init # follow prompts
Add a format script in [Link] :
{
"scripts": {
"format": "prettier --write \"**/*.{js,css,html,json,md}\""
}
}
Build tools (overview) - Vite: lightning‑fast dev server + build. - Webpack: mature bundler with rich
ecosystem.
Quick start with Vite:
npm create vite@latest my-app -- --template vanilla
cd my-app
npm install
npm run dev
Practice 1. Split utility functions into [Link] and import them in [Link] . 2. Initialize an npm project
and add a format script with Prettier.
Chapter 12: Error Handling
try...catch...finally
try {
[Link]('{ bad json }');
} catch (err) {
[Link]('Parsing failed:', [Link]);
} finally {
15
[Link]('Cleanup runs regardless');
}
Throwing custom errors
function withdraw(balance, amount) {
if (amount > balance) {
throw new Error('Insufficient funds');
}
return balance - amount;
}
try {
withdraw(100, 150);
} catch (e) {
[Link]([Link]);
}
Custom Error class
class ValidationError extends Error {
constructor(message) {
super(message);
[Link] = 'ValidationError';
}
}
function mustBeEmail(str) {
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(str)) {
throw new ValidationError('Invalid email');
}
return str;
}
Practice 1. Wrap a fetch call in try/catch and print friendly messages for network vs. parsing errors.
2. Create a RangeError when a function receives an out‑of‑range index.
Project 2: Weather App (Part 2 concepts)
Goal: Fetch and display current weather for a city (or your coordinates). Demonstrates fetch , async/
await , DOM updates, and error handling.
16
HTML
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Weather</title>
<style>
body { font-family: system-ui; max-width: 700px; margin: 2rem auto; }
#status { margin-top: 1rem; }
.card { border: 1px solid #ddd; padding: 1rem; border-radius: 8px; }
</style>
</head>
<body>
<h1>Weather</h1>
<form id="form">
<input id="city" placeholder="Enter city (e.g., Dhaka)" />
<button>Get Weather</button>
<button type="button" id="geo">Use My Location</button>
</form>
<div id="status"></div>
<div id="result" class="card" hidden></div>
<script type="module" src="[Link]"></script>
</body>
</html>
[Link] (uses Open‑Meteo, no API key required)
const form = [Link]('form');
const cityInput = [Link]('city');
const statusEl = [Link]('status');
const resultEl = [Link]('result');
const geoBtn = [Link]('geo');
const setStatus = (msg) => ([Link] = msg);
const showCard = (html) => { [Link] = html; [Link] =
false; };
async function geocodeCity(name) {
// Geocoding via Open‑Meteo (no key)
const url = `[Link]
{encodeURIComponent(name)}&count=1`;
const res = await fetch(url);
if (![Link]) throw new Error('Failed to geocode city');
17
const data = await [Link]();
if (![Link]?.length) throw new Error('City not found');
const { latitude, longitude, name: city, country } = [Link][0];
return { latitude, longitude, city, country };
}
async function getWeather(lat, lon) {
const url = `[Link]
&longitude=${lon}
¤t=temperature_2m,relative_humidity_2m,apparent_temperature,wind_speed_10m`;
const res = await fetch(url);
if (![Link]) throw new Error('Weather fetch failed');
const data = await [Link]();
return [Link];
}
function renderWeather(place, current) {
const { temperature_2m: t, relative_humidity_2m: rh, apparent_temperature:
feels, wind_speed_10m: wind } = current;
return `
<h2>${[Link] || 'Your location'}${[Link] ? ', ' +
[Link] : ''}</h2>
<ul>
<li><strong>Temperature:</strong> ${t} °C</li>
<li><strong>Feels like:</strong> ${feels} °C</li>
<li><strong>Humidity:</strong> ${rh} %</li>
<li><strong>Wind:</strong> ${wind} km/h</li>
</ul>
`;
}
[Link]('submit', async (e) => {
[Link]();
const city = [Link]();
if (!city) return;
try {
setStatus('Looking up city…');
const place = await geocodeCity(city);
setStatus('Fetching weather…');
const current = await getWeather([Link], [Link]);
showCard(renderWeather(place, current));
setStatus('');
} catch (err) {
setStatus([Link]);
}
});
[Link]('click', () => {
18
if (![Link]) {
setStatus('Geolocation not supported');
return;
}
setStatus('Finding your location…');
[Link](async (pos) => {
const { latitude, longitude } = [Link];
try {
setStatus('Fetching weather…');
const current = await getWeather(latitude, longitude);
showCard(renderWeather({}, current));
setStatus('');
} catch (err) {
setStatus([Link]);
}
}, () => setStatus('Permission denied or unavailable'));
});
Stretch ideas: Display a 5‑day forecast; add loading spinners; cache the last result in localStorage .
Best Practices Recap
• Prefer const / let to var .
• Use strict equality === and explicit conversions.
• Keep functions small and pure when possible.
• Avoid mutating arrays/objects; create new copies.
• Catch and handle errors; show helpful messages.
• Split code into modules; keep a tidy project structure.
• Lint and format your code automatically.
Next Steps
• Build more small apps: a calculator, notes app, image gallery, quiz game.
• Learn a framework (React/Vue/Svelte) after you’re comfortable with vanilla JS.
• Explore TypeScript for type safety in larger codebases.
Happy coding! 👩💻👨💻
19