JavaScript Fundamentals Explained Simply
JavaScript has accumulated a lot of syntax over thirty years, but day-to-day work uses a narrow slice of it. This guide covers that slice: how values are declared, how functions behave, how to work with arrays, and how asynchronous code actually runs.
Declaring values
Use const by default and let when a value is reassigned. There is no modern reason to write var: it ignores block scope, which produces bugs that are hard to see.
const rate = 0.08; // cannot be reassigned
let total = 0; // will change
total = 100 * (1 + rate);
const prevents reassignment, not mutation. An array declared with const can still have items pushed into it — what cannot change is which array the name points at.
Functions and arrow functions
function area(width, height) {
return width * height;
}
const areaArrow = (width, height) => width * height;
Arrow functions are shorter and, importantly, do not create their own this. That is why they are the right choice inside callbacks and class methods that pass functions around. A traditional function declaration is hoisted, meaning you can call it before the line where it is defined; arrow functions assigned to a const are not.
Default parameters and rest arguments remove a lot of defensive code:
function invoice(amount, currency = 'CAD', ...notes) {
return `${amount} ${currency} ${notes.join('; ')}`;
}Working with arrays
Four methods cover most data work. They all return a new array or value rather than modifying the original, which makes them safe to chain.
const orders = [
{ id: 1, total: 120, paid: true },
{ id: 2, total: 80, paid: false },
{ id: 3, total: 200, paid: true },
];
orders.filter(o => o.paid); // keep matching items
orders.map(o => o.total); // transform each item
orders.reduce((sum, o) => sum + o.total, 0); // collapse to one value
orders.find(o => o.id === 2); // first match, or undefined
Destructuring and spread keep object work readable:
const { id, total } = orders[0];
const updated = { ...orders[0], paid: false }; // copy with one changeAsynchronous code
JavaScript runs on a single thread. Anything slow — a network request, a file read, a timer — is handed off and its result arrives later. A promise represents that future result.
async function loadUser(id) {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
return response.json();
}
try {
const user = await loadUser(42);
console.log(user.name);
} catch (error) {
console.error('Could not load the user:', error.message);
}
Two details catch people out. First, fetch only rejects on network failure — a 404 or a 500 still resolves, so you must check response.ok yourself. Second, await inside a loop runs requests one after another. When the requests are independent, start them together:
const users = await Promise.all(ids.map(loadUser));Touching the page
const button = document.querySelector('#save');
button.addEventListener('click', (event) => {
event.preventDefault();
document.querySelector('#status').textContent = 'Saved';
});
Prefer textContent over innerHTML whenever you insert text. innerHTML parses whatever you give it as markup, so any value that came from a user or an API can inject script. If you must build markup, escape the values first.
Reading and writing the DOM is comparatively slow. In a loop, build a string or a document fragment and insert once, rather than appending inside each iteration.
Mistakes worth avoiding early
- Comparing with
==. Use===, which does not coerce types, and avoid the surprise that'' == 0is true. - Forgetting that
typeof nullreturns'object'. Check for null explicitly. - Mutating an array while looping over it. Build a new one instead.
- Leaving
console.login production code that handles personal data. - Storing anything sensitive in
localStorage. It is readable by any script on the page.
Common questions
Should I learn TypeScript next?
Once you are comfortable with functions, objects and async code, yes. TypeScript is JavaScript plus a type checker, and most of the learning curve is the type system rather than new runtime behaviour.
Do I need a framework to build something real?
No. Plain JavaScript handles forms, fetch calls and interactive widgets well. Frameworks earn their keep when an application has a lot of shared, changing state across many views.
Keep reading
HTML Basics: The Elements Every Page Uses
A practical introduction to HTML structure, the elements you use every day, forms, and the accessibility habits that keep pages working.
APIs Explained: Requests, Auth and Errors
What an API actually is, how HTTP requests and responses work, how authentication is handled, and how to consume an API without fragile code.
Using AI Coding Assistants Safely
Where AI assistants genuinely speed up development, where they quietly cost time, and a review process that keeps generated code safe to ship.
Spotted something out of date? Send a correction — guides are revised rather than quietly deleted.