Lecture 1 / 12
Lecture 01 · Foundations

Introduction to JavaScript

Beginner ~30 min No prerequisites

What is JavaScript?

JavaScript (JS) is a high‑level, interpreted, multi‑paradigm language that powers the web. It was created in 1995 by Brendan Eich at Netscape and has since become the de‑facto language for client‑side scripting, server‑side development (Node.js), desktop apps (Electron), and much more.

✅ Why learn JavaScript?
JS runs everywhere – browsers, servers, mobile, IoT – and mastering it unlocks a huge ecosystem of libraries, frameworks and career opportunities.

Hello World – Your First JS Program

hello.js
console.log("Hello, World!");

Run it with Node.js (or open the file in a browser console):

terminal
# Run
node hello.js
▶ Output
Hello, World!

How JavaScript Executes

🎯 Exercise 1.1

Install Node.js, create hello.js with the snippet above, run it, and verify the output.

Lecture 02 · Foundations

Environment Setup

Beginner ~40 min Requires: Lecture 01

Running JavaScript in the Browser

All modern browsers have a built‑in JavaScript engine. Open the developer console (F12 → “Console”) and type code directly.

browser console
console.log('Hello from the browser!');

Node.js – JavaScript on the Server

Node.js bundles the V8 engine with a set of core modules (file system, networking, etc.). After installing from nodejs.org you can run any .js file with the node command.

# Install (macOS/Linux)
brew install node

# Verify version
node -v
npm -v

Package Management with npm

npm (Node Package Manager) lets you install third‑party libraries.

# Initialise a new project
npm init -y

# Install a library (e.g., lodash)
npm install lodash

# Run a script defined in package.json
npm run start
ℹ️ npx

Run package binaries without installing them globally: npx create-react-app my-app.

Editor Recommendations

🎯 Exercise 2.1

Initialise a new npm project, install lodash, and write a script index.js that imports lodash and logs _.shuffle([1,2,3,4,5]) to the console.

Lecture 03 · Foundations

Variables & Data Types

Beginner ~45 min Requires: Lecture 02

Declaring Variables

Three main keywords:

variables.js
var legacy = 10;
let mutable = 20;
const immutable = 30;

console.log(legacy, mutable, immutable);

Primitive Types

Type Checking

typecheck.js
let val = '123';
console.log(typeof val);     // "string"

val = 123;
console.log(typeof val);     // "number"

val = null;
console.log(typeof val);     // "object" (quirk)

Constants and Immutability

Only the binding of a const cannot change. For objects/arrays the contents are still mutable unless you freeze them:

freeze.js
const arr = [1, 2];
arr.push(3);               // works

Object.freeze(arr);
arr.push(4);               // TypeError: Cannot add property 3, object is not extensible
🎯 Exercise 3.1

Create a script that declares variables of each primitive type, prints their type using typeof, then attempts to reassign a const and observes the error.

Lecture 04 · Foundations

Operators & Expressions

Beginner ~40 min Requires: Lecture 03

Arithmetic Operators

Operator Meaning Example Result
+ Addition / concatenation 5 + 3 8
- Subtraction 5 - 3 2
* Multiplication 5 * 3 15
/ Division 7 / 2 3.5
% Remainder 7 % 2 1

String Concatenation & Template Literals

concat.js
let a = "Hello";
let b = "World";

console.log(a + ", " + b);                   // Hello, World
console.log(`\${a}, \${b}!`);            // Hello, World!

Comparison & Logical Operators

Operator Meaning Example Result
=== Strict equality (no coercion) 5 === "5" false
!== Strict inequality 5 !== 5 false
== Loose equality (type coercion) 5 == "5" true
!= Loose inequality 5 != "5" false
&& Logical AND true && false false
|| Logical OR true || false true
! Logical NOT !true false

Assignment Operators

assign.js
let x = 5;
x += 3;   // x = 8
x *= 2;   // x = 16
x %= 5;   // x = 1

Type Coercion Gotchas

coercion.js
console.log(1 + 2 + "3");     // "33"
console.log("3" - 2);            // 1 (string converted to number)
🎯 Exercise 4.1

Write a program that reads two numbers with prompt() (or readline-sync on Node) and prints the sum, difference, product, quotient, remainder and a truthy/falsy test of the result.

Lecture 05 · Foundations

Control Flow

Beginner ~45 min Requires: Lecture 04

If / else if / else

ifelse.js
let score = 85;

if (score >= 90) {
    console.log("Grade A");
} else if (score >= 80) {
    console.log("Grade B");
} else {
    console.log("Needs improvement");
}

Switch Statement

switch.js
let day = 'Monday';

switch (day) {
    case 'Monday':
        console.log('Start of the week');
        break;
    case 'Friday':
        console.log('Almost weekend');
        break;
    default:
        console.log('Just another day');
}

Loops

for loop

for_loop.js
for (let i = 1; i <= 5; i++) {
    console.log(i);
}

while loop

while_loop.js
let n = 1;
while (n <= 100) {
    console.log(n);
    n *= 2;
}

do…while loop

do_while.js
let password;
do {
    password = prompt('Enter password (type 1234 to quit):');
} while (password !== '1234');

break & continue

🎯 Exercise 5.1

Write a program that prints the multiplication table of a number entered by the user (1‑12). Then create a do…while loop that repeatedly asks for a secret word until the user enters open-sesame.

Lecture 06 · Core Concepts

Functions

Intermediate ~55 min Requires: Lecture 05

Function Declarations & Expressions

Two common syntaxes:

functions.js
function add(a, b) {
    return a + b;
}

const multiply = (a, b) => a * b;          // arrow function

console.log(add(3, 4));          // 7
console.log(multiply(5, 6));   // 30

Default Parameters & Rest Parameters

params.js
function greet(name = 'World') {
    console.log(`Hello, \${name}!`);
}
greet();                // Hello, World!
greet('Alice');       // Hello, Alice!

function sumAll(...nums) {
    return nums.reduce((a, b) => a + b, 0);
}
console.log(sumAll(1, 2, 3)); // 6

Higher‑Order Functions & Callbacks

A function can receive another function as an argument or return one.

callback.js
function fetchData(url, callback) {
    setTimeout(() => {
        const data = `Data from \${url}`;
        callback(data);
    }, 1000);
}

fetchData('/api', result => {
    console.log(result);
});
✅ Arrow functions vs regular functions
Arrow functions inherit this from the surrounding scope, while regular functions have their own this binding depending on how they are called.
🎯 Exercise 6.1

Implement a recursive factorial(n) function (using both a function declaration and an arrow function). Then write a higher‑order function applyTwice(fn, x) that returns fn(fn(x)) and test it with the factorial function.

Lecture 07 · Core Concepts

Objects & Prototypes

Intermediate ~55 min Requires: Lecture 06

Object Literals

Key/value pairs enclosed in {}. Property names can be strings or identifiers.

object.js
const user = {
    name: "Bob",
    age: 30,
    isAdmin: true,
    greet() {
        console.log(`Hi, I'm \${this.name}`);
    }
};

console.log(user.name);    // Bob
user.greet();           // Hi, I’m Bob

Constructor Functions & Classes

Before ES6, objects were created via constructor functions and the new keyword. ES6 introduced class syntax which is syntactic sugar over the prototype chain.

class.js
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    greet() {
        console.log(`\${this.name} says hello!`);
    }
}

const alice = new Person('Alice', 28);
alice.greet();    // Alice says hello!

Prototypal Inheritance

Every object has an internal [[Prototype]] (accessible via Object.getPrototypeOf or __proto__). Adding properties to the prototype makes them shared.

prototype.js
function Animal(type) {
    this.type = type;
}

Animal.prototype.speak = function() {
    console.log(`\${this.type} makes a sound`);
};

const dog = new Animal('Dog');
dog.speak();   // Dog makes a sound
⚠️ Beware of shared mutable properties
If you put an object or array on a prototype, all instances will share the same reference, leading to unexpected side‑effects.
🎯 Exercise 7.1

Create a Vehicle class with make, model and a method info(). Extend it with an ElectricVehicle subclass that adds a batteryLevel property and overrides info() to also show the battery.

Lecture 08 · Core Concepts

Arrays & Higher‑Order Functions

Intermediate ~55 min Requires: Lecture 07

Array Basics

Arrays are ordered collections, created with [] or new Array().

array.js
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.length);       // 5
console.log(numbers[0]);         // 1

Common Array Methods

higher_order.js
const nums = [1, 2, 3, 4, 5];

// map – double each number
const doubled = nums.map(n => n * 2);
console.log(doubled);               // [2,4,6,8,10]

// filter – keep evens
const evens = nums.filter(n => n % 2 === 0);
console.log(evens);                // [2,4]

// reduce – sum
const sum = nums.reduce((acc, cur) => acc + cur, 0);
console.log(sum);                 // 15

Spread & Rest Operators

Use ... to expand or collect elements.

spread.js
const a = [1, 2];
const b = [3, 4];
const combined = [...a, ...b];  // [1,2,3,4]

function logAll(...values) {
    console.log(values);
}
logAll(5, 6, 7);   // [5,6,7]
🎯 Exercise 8.1

Write a function unique(arr) that returns a new array with duplicate values removed (use Set or filter). Then write a groupBy(arr, keyFn) that groups objects by a derived key and returns an object of arrays.

Lecture 09 · Core Concepts

Asynchronous JavaScript

Intermediate ~60 min Requires: Lecture 08

Callbacks

Functions passed to async APIs that run once the operation completes.

callback_async.js
function delayedLog(msg, delay, cb) {
    setTimeout(() => {
        console.log(msg);
        if (cb) cb();
    }, delay);
}

delayedLog('First', 1000, () => {
    delayedLog('Second', 500);
});

Promises

Represent a value that may become available in the future. They can be chained and handle errors with catch.

promise.js
function fetchNumber() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const n = 42;
            if (n) resolve(n);
            else reject('No number');
        }, 800);
    });
}

fetchNumber()
    .then(value => console.log('Got', value))
    .catch(err => console.error(err));

Async / Await

Syntactic sugar over promises; makes asynchronous code look synchronous.

async_await.js
async getData() {
    try {
        const res = await fetch('https://api.github.com/users/octocat');
        const data = await res.json();
        console.log(data);
    } catch (e) {
        console.error(e);
    }
}
getData();
🎯 Exercise 9.1

Write a function fetchJson(url) that returns a promise resolving to parsed JSON (use fetch). Then consume it with both .then/.catch and with async/await to display the result.

Lecture 10 · Advanced

DOM Manipulation & Events

Intermediate ~55 min Requires: Lecture 09

The Document Object Model

The DOM is a tree‑like representation of the HTML page. You can query and modify nodes with the document API.

Selecting Elements

select.js
const header = document.querySelector('h1');
const items = document.querySelectorAll('.item');
const byId = document.getElementById('main');

Modifying Content

modify.js
header.textContent = 'New Title';
header.style.color = 'rebeccapurple';

const newDiv = document.createElement('div');
newDiv.classList.add('card');
newDiv.innerHTML = `<p>Hello</p>`;
document.body.appendChild(newDiv);

Event Handling

Attach listeners with addEventListener. Event objects provide details (type, target, etc.).

events.js
document.querySelector('button').addEventListener('click', e => {
    alert(`Clicked! X: \${e.clientX}`);
});

window.addEventListener('resize', () => {
    console.log('Window resized. New size:', window.innerWidth);
});
🎯 Exercise 10.1

Build a simple counter app: an HTML page with a number display and two buttons “+” and “‑”. Clicking the buttons updates the number and stores the current value in localStorage so the count persists across reloads.

Lecture 11 · Advanced

Modules & Build Tools

Advanced ~60 min Requires: Lecture 10

ES6 Modules

Use export and import. Native support in browsers (with type="module") and in Node.js (with .mjs or "type":"module" in package.json).

math.mjs
export function add(a, b) {
    return a + b;
}

export const PI = 3.1415926535;
main.mjs
import { add, PI } from './math.mjs';

console.log(add(2, 3));    // 5
console.log(PI);            // 3.14159...

CommonJS (Node.js legacy)

Uses module.exports and require(). Still works alongside ES6 modules.

math.cjs
function multiply(a, b) {
    return a * b;
}
module.exports = { multiply };

Bundlers (Webpack, Vite, Parcel)

Combine multiple modules, transpile with Babel, and generate production‑ready assets.

# Example with Vite (fast dev server)
npm create vite@latest my-app -- --template vanilla
cd my-app
npm install
npm run dev

Transpiling Modern JS (Babel)

Convert ES2023+ syntax to older JavaScript that runs on older browsers.

# Install Babel
npm install --save-dev @babel/core @babel/cli @babel/preset-env

# .babelrc
{
  "presets": ["@babel/preset-env"]
}
🎯 Exercise 11.1

Set up a tiny project with Vite (or Webpack) using ES modules. Create two modules (utils.js exporting a helper, and app.js importing it) and run the development server to see the live reload.

Lecture 12 · Capstone

Capstone Project – Interactive To‑Do List

Advanced ~90 min Requires: All Lectures

In this project you will build a **single‑page** JavaScript application that lets the user manage a to‑do list. The app will demonstrate everything you’ve learned: modules, DOM manipulation, event handling, local storage, async operations, and modern JavaScript syntax.

Feature Checklist

Project Skeleton

project layout
todo-app/
├── index.html
├── styles.css
├── src/
│   ├── app.js          /* entry point */
│   ├── store.js        /* localStorage handling */
│   └── ui.js           /* DOM rendering & events */
└── package.json        /* optional – for build tools */

Starter Code – index.html

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Todo List</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="app">
        <h1>Todo List</h1>
        <input id="new-task" type="text" placeholder="What needs to be done?">
        <ul id="task-list"></ul>
        <div class="filters">
            <button data-filter="all">All</button>
            <button data-filter="active">Active</button>
            <button data-filter="completed">Completed</button>
        </div>
    </div>

    <script type="module" src="src/app.js"></script>
</body>
</html>

Basic UI Module (ui.js)

ui.js
import { getTasks, addTask, toggleTask, deleteTask, setFilter } from './store.js';

const taskList = document.getElementById('task-list');
const newTaskInput = document.getElementById('new-task');
const filterButtons = document.querySelectorAll('.filters button');

function render() {
    const tasks = getTasks();
    taskList.innerHTML = '';
    tasks.forEach(t => {
        const li = document.createElement('li');
        li.className = t.done ? 'done' : '';
        li.innerHTML = `\${t.text}
            <button class="toggle">\${t.done ? '↩' : '✓'}</button>
            <button class="del">✕</button>`;

        li.querySelector('.toggle').addEventListener('click', () => {
            toggleTask(t.id);
            render();
        });
        li.querySelector('.del').addEventListener('click', () => {
            deleteTask(t.id);
            render();
        });

        taskList.appendChild(li);
    });
}

newTaskInput.addEventListener('keydown', e => {
    if (e.key === 'Enter' && newTaskInput.value.trim()) {
        addTask(newTaskInput.value.trim());
        newTaskInput.value = '';
        render();
    }
});

filterButtons.forEach(btn => {
    btn.addEventListener('click', () => {
        setFilter(btn.dataset.filter);
        render();
    });
});

render();

Store Module (store.js) – persists in localStorage

store.js
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
let filter = 'all';

function save() {
    localStorage.setItem('tasks', JSON.stringify(tasks));
}

export function getTasks() {
    if (filter === 'active') return tasks.filter(t => !t.done);
    if (filter === 'completed') return tasks.filter(t => t.done);
    return tasks;
}

export function addTask(text) {
    const id = Date.now();
    tasks.push({id, text, done: false, createdAt: new Date()});
    save();
}

export function toggleTask(id) {
    const t = tasks.find(x => x.id === id);
    if (t) t.done = !t.done;
    save();
}

export function deleteTask(id) {
    tasks = tasks.filter(x => x.id !== id);
    save();
}

export function setFilter(mode) {
    filter = mode;
}

Application Entry (app.js)

app.js
import './ui.js';   // UI module runs immediately and wires everything up
🚀 Extensions
  • Add a simple backend (Node Express) that stores tasks in a JSON file and syncs via HTTP.
  • Use a CSS framework (Tailwind, Bulma) for a prettier UI.
  • Write unit tests for store.js using Jest.
🎯 Final Challenge

Extend the app with a “Due Date” field on each task. Show a visual indicator (e.g., red background) for tasks that are overdue. Store the date in ISO format, and format it nicely using Intl.DateTimeFormat.