The language everything's built on. A few quirks, a handful of rules, and once they click — most of the weirdness goes away.
JavaScript has eight basic types. Most of the time you'll only touch the first three.
| string | 'text' |
| number | 42 |
| boolean | true / false |
| undefined | let x; |
| null | null |
| object | { key: 'value' } |
| array | [1, 2, 3] |
| symbol | Symbol('id') |
Object groups stuff together. Array is technically a type of object, just for lists. Symbol is the weird one — unique IDs, you'll rarely need it.
Three ways to declare a variable. They behave differently and yes, that matters.
| var | function scoped (old, avoid) |
| let | block scoped (can change) |
| const | block scoped (can't reassign) |
var is the old one. It's got function scope and weirdly unpredictable behaviour, so we don't really use it anymore.
let is for when you know the value's going to change. const is when it shouldn't.
Both mean "nothing", but the difference is intention.
undefined = a variable exists but hasn't been given a value. JavaScript handed it to you. If you write let x; — that's undefined.
null = you decided the value should be empty. You handed it over on purpose.
== compares values but quietly converts types if it has to. Sometimes that's fine. Often it's a bug waiting to happen.
=== compares value and type. No magic conversions.
'5' == 5 // true (??) '5' === 5 // false
A function is reusable code. You give it some inputs, it gives you a result. The whole point is to not repeat the same logic in five different places.
Three common ways to write one:
// 1. function declaration function add(a, b) { return a + b; } // 2. function expression const add = function(a, b) { return a + b; }; // 3. arrow function (modern, short) const add = (a, b) => a + b;
A template for making lots of objects with the same shape. You call it with new and get a fresh instance every time. Handy when you've got a bunch of things that all need the same properties and behaviour.
A mode that makes JavaScript stricter — and honestly, kinder. It catches dumb mistakes early, like using a variable you forgot to declare.
In bigger projects it's basically free safety. Toss it at the top of the file and move on.
'use strict';
An array is an ordered list of values. Good for when order matters or you're iterating.
A Map stores key→value pairs. Better when you need to grab a value fast by its key.
A callback is a function you pass into another function, that gets called later. Super common in async code — like running something after data comes back from a server.
getData(function(data) { // runs once data // is ready });
It's the original "do this thing, but later" pattern.
Splitting your code into separate files. Instead of one huge mess, you export the bits you want to share and import them where you need them.
// math.js export function add(a, b) { return a + b; } // app.js import { add } from './math.js';
Cleaner. Easier to maintain. Reusable. Win-win-win.
How you decide what runs, and when. Three tools do most of the heavy lifting:
A web framework for Node.js. It takes the boring parts of building a back-end and just handles them — routing, requests, responses. You bring the logic.
Express.js is the framework you use on top of Node.js to build back-ends and APIs. Without it, you'd be wiring up routing and request handling from scratch — and nobody wants that.
The flow's simple: a request comes in, Express matches it to the right route, runs whatever middleware is in the way, hits your handler function, and sends a response back. That's the whole job.
// GET HOME PAGE router.get("/", function(req, res) { // handle logic // fetch data if needed res.send('index.html'); });
A way to keep your code from turning into spaghetti. Three roles, each handling one thing.
Controller — the middleman. Takes the request, asks the Model for data, hands the result to the View.
Model — handles data and database stuff. Users, products, whatever.
View — what the user actually sees. Usually HTML.
A layout is the shared frame — header, footer, the stuff that's the same on every page. A partial is a reusable chunk like a navbar or a card you drop in wherever. Less duplication, less pain.
Middleware is a function that sits between the request and the response. Logging, auth, parsing data — anything you want to happen on the way in.
app.use((req, res, next) => { console.log("Request received"); next(); });
next() hands the request along to the next step. That's how you stack logic, one piece at a time.
GET = read
POST = send / create
GET to grab. POST to give. That's most of it.
The server's way of telling you how it went. Three you'll see constantly:
Where the actual stuff lives. Users, orders, posts, all of it. Relational databases keep data in tables — and SQL is how you talk to them.
Stores data in tables — rows and columns, like a tidy spreadsheet. The "relational" part means tables can be linked to each other. Users to orders, posts to authors, all that.
Good fit when your data has clear structure and clear connections.
Structured Query Language. The language you use to talk to a relational database. Read, write, update, delete — all of it goes through SQL.
You'll spend most of your time on these four:
// READ SELECT * FROM users; // CREATE INSERT INTO users (name) VALUES ('Sara'); // UPDATE UPDATE users SET name = 'Alex' WHERE id = 1; // DELETE DELETE FROM users WHERE id = 1;
Then there's CREATE / DROP / ALTER for the tables themselves — making them, removing them, changing them.
A primary key uniquely identifies each row in a table. No two rows can have the same value in that column. Almost always an id field.
CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(100) );
A foreign key is how you connect two tables. It points at the primary key of another table — saying "this row belongs to that row over there."
CREATE TABLE orders ( id INT PRIMARY KEY, user_id INT, FOREIGN KEY (user_id) REFERENCES users(id) );
Here, every order is tied to a user via user_id. That's the relationship.
Three flavours, and you'll see all of them.
When you delete a row, anything connected to it gets deleted too — automatically. You set it up on the foreign key.
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
Stops you from leaving "orphan" rows lying around — orders pointing at users that don't exist anymore. Tidy.
An index is like the index in the back of a book. Instead of reading every row, the database jumps straight to the right one.
Big tables = slow searches without indexes. Add one on a column you query a lot, and things speed up a lot.