Learn JavaScript Fundamentals – A Beginner’s Guide

JavaScript is the language that brings your website to life. If HTML is the structure and CSS is the style, JavaScript is the behavior. It enables you to respond to user actions, update the UI, fetch data from APIs, and perform additional tasks. This guide walks through JavaScript fundamentals with examples, and MDN’s JavaScript guide is a good companion.
Whether you’re aiming to become a frontend engineer or want to build interactive web pages, learning JavaScript is a must. Let’s start from the very beginning and walk through all the core fundamentals you need to know.
This article will be divided into three main parts for simplicity:
- Javascript Fundamentals
- Objects and Data Types
- Promises / Async / Awaits
Before we begin, I want to mention that this fundamental guide may seem a bit overwhelming, however, the goal here isn’t to memorize and rehearse all of these topics, but instead, use them in practical web applications, and naturally, you will recognize patterns, and where and when to apply certain things.
With that out of the way, let’s begin.
Javascript Fundamentals
Hello World in JavaScript
The simplest way to run JavaScript is inside a browser using the <script> tag.
<script>
alert("Hello, world!");
</script>
This will show a pop-up message when the page loads.
Basic Code Structure
JavaScript code is composed of statements that end with semicolons. You don’t always need semicolons, but it’s good practice to use them.
let message = "Welcome!";
alert(message);
Variables
You can store values using. let, const, or var (which is older and now rarely used).
let name = "Sarah";
const age = 28;
Use let If the value changes, const If it won’t.
Data Types
Common data types in JavaScript:
- String:
"Hello" - Number:
42,3.14 - Boolean:
true,false - Null: intentional absence of value
- Undefined: declared but not assigned
- Object: complex data structures
- Array: list of values
Interaction: alert, prompt, and confirm
alert("This is an alert!");
prompt("What is your name?");
confirm("Are you sure?");
alert shows a message. prompt Asks for input. confirm asks for yes/no and returns true or false.
Type Conversions
JavaScript is loosely typed. It automatically converts types, but you can also do it manually.
Number("42"); // 42
String(123); // "123"
Boolean(0); // false
Basic Math Operators
let sum = 10 + 5;
let difference = 10 - 3;
let product = 4 * 2;
let quotient = 20 / 5;
let remainder = 10 % 3;
You can also use ++ and -- to increment or decrement a value.
Comparison Operators
5 > 3 // true
10 <= 10 // true
"5" == 5 // true (loose equality)
"5" === 5 // false (strict equality)
Use === to avoid unexpected type conversions.
Conditional Branching: if and ?
let age = 20;
if (age >= 18) {
alert("You can enter.");
} else {
alert("Too young.");
}
// Ternary version
let message = age >= 18 ? "Allowed" : "Denied";
Logical Operators
Logical operators are used to combine multiple boolean expressions.
let isLoggedIn = true;
let isAdmin = false;
if (isLoggedIn && isAdmin) {
alert("Welcome, admin");
} else {
alert("Access denied");
}
Nullish Coalescing Operator
The nullish operator ?? returns the right-hand value only if the left-hand value is null or undefined.
let nickname = null;
let displayName = nickname ?? "Guest";
alert(displayName); // "Guest"
While Loop
A while loop repeats as long as the condition is true.
let i = 0;
while (i < 3) {
console.log(i);
i++;
}
For Loop
A for loop is great for running a block of code a specific number of times.
for (let i = 0; i < 3; i++) {
console.log("Step " + i);
}
Switch Statement
A switch is a clean way to handle multiple possible values of a single variable.
let color = "blue";
switch (color) {
case "red":
console.log("Color is red");
break;
case "blue":
console.log("Color is blue");
break;
default:
console.log("Color not recognized");
}
Functions
A function lets you group code together so you can reuse it.
function sayHi(name) {
alert("Hi, " + name);
}
sayHi("Alex");
Function Expressions
You can also assign a function to a variable.
const sayBye = function(name) {
alert("Goodbye, " + name);
};
sayBye("Alex");
Arrow Functions
Arrow functions are a shorter way to write function expressions, often used for quick tasks.
const sayThanks = (name) => {
alert("Thanks, " + name);
};
sayThanks("Alex");
Putting It All Together
function greetUser(name) {
if (!name) {
name = prompt("What's your name?") ?? "Guest";
}
const welcomeMessage = (name === "Admin")
? "Welcome back, Admin"
: "Welcome, " + name;
alert(welcomeMessage);
}
for (let i = 0; i < 2; i++) {
greetUser();
}
This example prompts the user for their name (if not provided), uses the nullish operator to default to “Guest”, checks if the user is “Admin” using a ternary operator, and then runs the greeting twice using a for loop. It brings together variables, conditionals, prompts, functions, nullish, ternary, and loops — all in one place.
This covers the absolute basics you need to get started. Next, we’ll dig into how to write better quality code and work with objects, arrays, and more.
Objects and Data Types
Objects
Objects are used to group related data and functionality together.
let user = {
name: "Alice",
age: 30,
greet: function() {
alert("Hi, I'm " + this.name);
}
};
user.greet();
Object References and Copying
Objects are copied by reference, not by value.
let person = { name: "Bob" };
let clone = person;
clone.name = "John";
console.log(person.name); // "John" — same object
Garbage Collection
JavaScript automatically cleans up memory when objects are no longer reachable. You don’t have to manually manage memory.
This in Methods
Inside a method, this refers to the object that owns the method.
let car = {
brand: "Tesla",
show: function() {
alert(this.brand);
}
};
car.show();
Constructor Function with new
Use new with a constructor function to create multiple similar objects.
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user1 = new User("Sarah");
alert(user1.name);
Optional Chaining
Use ?. to safely access deeply nested properties.
let user = {};
console.log(user.profile?.email); // undefined, no error
Symbols
Symbol is a unique identifier. Often used for hidden properties in objects.
let id = Symbol("id");
let user = {
[id]: 123
};
console.log(user[id]);
Methods of Primitives
Primitive values like strings and numbers can use methods because JavaScript wraps them temporarily.
let message = "hello";
console.log(message.toUpperCase()); // "HELLO"
Numbers
JavaScript has one number type. It handles integers and floats.
let num = 42;
let price = 19.99;
Strings
let str = "JavaScript";
console.log(str.length); // 10
console.log(str.includes("Script")); // true
Arrays
Arrays store ordered collections.
let colors = ["red", "blue", "green"];
console.log(colors[1]); // "blue"
Common Array Methods
let numbers = [1, 2, 3, 4];
numbers.push(5); // [1,2,3,4,5]
numbers.pop(); // [1,2,3,4]
numbers.map(x => x * 2); // [2,4,6,8]
numbers.filter(x => x % 2 === 0); // [2,4]
Iterables
Arrays, strings, and some objects can be looped over using for...of.
for (let char of "hello") {
console.log(char);
}
Map and Set
Map: Like an object, but keys can be anything.
let map = new Map();
map.set("name", "Alex");
console.log(map.get("name"));
Set: A collection of unique values.
let set = new Set();
set.add(1);
set.add(1);
console.log(set.size); // 1
WeakMap and WeakSet
These work like Map and Set, but the keys must be objects, and they don’t prevent garbage collection.
Object.keys, Object.values, Object.entries
let user = { name: "Jane", age: 25 };
console.log(Object.keys(user)); // ["name", "age"]
console.log(Object.values(user)); // ["Jane", 25]
console.log(Object.entries(user)); // [["name", "Jane"], ["age", 25]]
Destructuring Assignment
You can pull values out of objects or arrays easily.
let user = { name: "Kyle", age: 22 };
let { name, age } = user;
let colors = ["red", "blue"];
let [first, second] = colors;
Date and Time
let now = new Date();
console.log(now.getFullYear());
JSON Methods
Used to convert data to and from JSON format.
let user = {
name: "Mia",
age: 30
};
let json = JSON.stringify(user); // Convert to JSON string
let parsed = JSON.parse(json); // Convert back to object
Fetching and Rendering Data From The Backend (Async Requests)
Callbacks (Before Promises)
Callbacks were the original way to handle asynchronous code in JavaScript.
function loadData(callback) {
setTimeout(() => {
callback("Data loaded");
}, 1000);
}
loadData((result) => {
console.log(result);
});
Callbacks work, but they quickly become messy and hard to manage — especially when you have nested operations.
Introduction to Promises
A promise is a built-in JavaScript object that represents a value that may be available now, later, or never.
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Success!"), 1000);
});
promise.then(result => console.log(result));
Promise Chaining
You can chain multiple .then() calls together to handle a sequence of asynchronous operations.
fetch("/api/user")
.then(response => response.json())
.then(user => {
console.log("User loaded", user);
return fetch(`/api/posts?user=${user.id}`);
})
.then(response => response.json())
.then(posts => console.log("Posts loaded", posts));
Error Handling with Promises
Use .catch() to handle any errors in the chain.
fetch("/api/unknown")
.then(res => res.json())
.catch(err => console.error("Something went wrong", err));
Promise API
JavaScript has a few powerful Promise utilities:
Promise.all([ ... ])– waits for all promises to finishPromise.race([ ... ])– resolves when the first promise resolvesPromise.allSettled([ ... ])– waits for all to finish, regardless of success/failure
Promisification
This means wrapping older callback-based functions in a promise for easier handling.
function loadScript(src) {
return new Promise((resolve, reject) => {
let script = document.createElement("script");
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error("Script load failed"));
document.head.append(script);
});
}
Microtasks
Promise callbacks are scheduled in the microtask queue, which runs after the current execution but before the next setTimeout or DOM event.
Promise.resolve().then(() => console.log("Microtask"));
setTimeout(() => console.log("Macrotask"), 0);
// Output: Microtask, then Macrotask
Async and Await
async functions let you write promise-based code as if it were synchronous.
async function loadUser() {
try {
let response = await fetch("/api/user");
let user = await response.json();
console.log(user);
} catch (err) {
console.error("Failed to load user", err);
}
}
Full Example: Fetching and Rendering Data
This example fetches data from a fake API and renders it on the page.
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: Arial;
padding: 20px;
}
.user {
border: 1px solid #ddd;
padding: 10px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<h2>Users List</h2>
<div id="users">Loading...</div>
<script>
async function fetchUsers() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
const users = await response.json();
const container = document.getElementById("users");
container.innerHTML = "";
users.forEach(user => {
const div = document.createElement("div");
div.className = "user";
div.innerHTML = `<strong>${user.name}</strong> <br /> ${user.email}`;
container.appendChild(div);
... premium content.