Chapter 5: JavaScript Basics 🚀
"JavaScript is the language of the web—it turns static pages into interactive experiences."
JavaScript is the programming language that brings websites to life. While HTML provides structure and CSS adds style, JavaScript adds behavior and interactivity. In this chapter, we'll explore the fundamental JavaScript concepts that form the foundation of modern web development.
Introduction to JavaScript
JavaScript was created in 1995 and has evolved to become one of the world's most popular programming languages. It runs in the browser, on servers (Node.js), and even powers desktop and mobile applications.
Adding JavaScript to HTML
There are three ways to include JavaScript in your web pages:
- Inline JavaScript:
<button onclick="alert('Hello, World!')">Click Me</button>
- Internal JavaScript:
<script> // JavaScript code goes here console.log("Hello from internal JavaScript!"); </script>
- External JavaScript (recommended):
<script src="script.js"></script>// In script.js console.log("Hello from external JavaScript!");
The Console
The browser's console is essential for JavaScript development:
// Output a message to the console
console.log("This is a log message");
// Output a warning
console.warn("This is a warning");
// Output an error
console.error("This is an error");
// Output an object in an expandable format
console.log({name: "John", age: 30});
// Measure time taken by operations
console.time("timer");
// ... some operations
console.timeEnd("timer");
Now, let's dive into the core JavaScript concepts.
Variable 📦
Variables are containers for storing data values.
Declaring Variables
In modern JavaScript, there are three ways to declare variables:
// Using let (recommended for variables that will change)
let age = 25;
age = 26; // Value can be changed
// Using const (for variables that won't change)
const PI = 3.14159;
// PI = 3; // Error! Can't reassign a constant
// Using var (older method, not recommended for new code)
var name = "John";
name = "Jane"; // Value can be changed
Variable Naming Rules
// Valid variable names
let firstName = "John";
let last_name = "Doe";
let $specialVar = 100;
let _privateVar = true;
let camelCaseIsPreferred = "yes";
// Invalid variable names
// let 1stPlace = "Gold"; // Can't start with a number
// let my-variable = "test"; // Can't use hyphens
// let let = "keyword"; // Can't use reserved keywords
Variable Scope
Scope determines where variables are accessible:
// Global scope
let globalVar = "I'm accessible everywhere";
function exampleFunction() {
// Function scope
let functionVar = "I'm only accessible inside this function";
if (true) {
// Block scope (with let/const)
let blockVar = "I'm only accessible inside this block";
var notBlockScoped = "I'm accessible throughout the function";
console.log(globalVar); // Accessible ✓
console.log(functionVar); // Accessible ✓
console.log(blockVar); // Accessible ✓
console.log(notBlockScoped); // Accessible ✓
}
console.log(globalVar); // Accessible ✓
console.log(functionVar); // Accessible ✓
// console.log(blockVar); // Error! Not accessible ✗
console.log(notBlockScoped); // Accessible ✓ (var ignores block scope)
}
console.log(globalVar); // Accessible ✓
// console.log(functionVar); // Error! Not accessible ✗
// console.log(blockVar); // Error! Not accessible ✗
// console.log(notBlockScoped); // Error! Not accessible ✗
Hoisting
JavaScript "hoists" declarations to the top of their scope:
// What you write:
console.log(hoistedVar); // undefined (not an error)
var hoistedVar = "I'm hoisted";
// How JavaScript interprets it:
// var hoistedVar;
// console.log(hoistedVar);
// hoistedVar = "I'm hoisted";
// let and const don't work the same way:
// console.log(notHoisted); // Error! Cannot access before initialization
// let notHoisted = "I'm not hoisted";
Type 🏷️
JavaScript has several data types for different kinds of values.
Primitive Types
// Number
let integer = 42;
let float = 3.14;
let infinity = Infinity;
let notANumber = NaN;
// String
let singleQuotes = 'Hello';
let doubleQuotes = "World";
let backticks = `Hello ${singleQuotes}`; // Template literal with variable interpolation
// Boolean
let isTrue = true;
let isFalse = false;
// Undefined (variable declared but no value assigned)
let notDefined;
console.log(notDefined); // undefined
// Null (intentional absence of any value)
let emptyValue = null;
// Symbol (unique identifier)
let uniqueSymbol = Symbol("description");
// BigInt (for integers larger than Number can handle)
let bigInteger = 9007199254740991n;
Complex Types
// Object
let person = {
firstName: "John",
lastName: "Doe",
age: 30,
isEmployed: true,
hobbies: ["reading", "hiking"],
address: {
street: "123 Main St",
city: "Anytown"
},
greet: function() {
return `Hello, my name is ${this.firstName}`;
}
};
// Accessing object properties
console.log(person.firstName); // Dot notation
console.log(person["lastName"]); // Bracket notation
console.log(person.address.city); // Nested properties
console.log(person.greet()); // Calling a method
// Array
let fruits = ["apple", "banana", "cherry"];
// Accessing array elements (zero-indexed)
console.log(fruits[0]); // "apple"
console.log(fruits[1]); // "banana"
console.log(fruits.length); // 3
// Arrays can contain mixed types
let mixed = [42, "hello", true, {key: "value"}, [1, 2, 3]];
Type Checking and Conversion
// Checking types
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (this is a known JS quirk)
console.log(typeof {}); // "object"
console.log(typeof []); // "object" (arrays are objects in JS)
console.log(typeof function(){}); // "function"
// Type conversion
let num = 42;
let str = String(num); // Convert to string: "42"
let bool = Boolean(num); // Convert to boolean: true (0 would be false)
let backToNum = Number("42"); // Convert to number: 42
// Implicit type conversion (coercion)
console.log("5" + 2); // "52" (number converted to string)
console.log("5" - 2); // 3 (string converted to number)
console.log("5" == 5); // true (loose equality)
console.log("5" === 5); // false (strict equality, no type conversion)
Special Number Methods and Properties
// Number methods
let num = 3.14159;
console.log(num.toFixed(2)); // "3.14" (rounds to 2 decimal places)
console.log(num.toPrecision(3)); // "3.14" (3 significant digits)
console.log(Number.isInteger(num)); // false
// Special number properties
console.log(Number.MAX_VALUE); // Largest possible number
console.log(Number.MIN_VALUE); // Smallest positive number
console.log(Number.POSITIVE_INFINITY); // Infinity
console.log(Number.NEGATIVE_INFINITY); // -Infinity
console.log(Number.NaN); // Not a Number
String Methods
let text = "Hello, World!";
// Basic string properties and methods
console.log(text.length); // 13
console.log(text.toUpperCase()); // "HELLO, WORLD!"
console.log(text.toLowerCase()); // "hello, world!"
// Finding substrings
console.log(text.indexOf("World")); // 7
console.log(text.includes("Hello")); // true
console.log(text.startsWith("Hello")); // true
console.log(text.endsWith("!")); // true
// Extracting substrings
console.log(text.slice(0, 5)); // "Hello"
console.log(text.substring(7, 12)); // "World"
console.log(text.split(", ")); // ["Hello", "World!"]
// Replacing content
console.log(text.replace("World", "JavaScript")); // "Hello, JavaScript!"
// Trimming whitespace
let paddedText = " padded ";
console.log(paddedText.trim()); // "padded"
Array Methods
let colors = ["red", "green", "blue"];
// Adding and removing elements
colors.push("yellow"); // Add to end: ["red", "green", "blue", "yellow"]
colors.pop(); // Remove from end: ["red", "green", "blue"]
colors.unshift("purple"); // Add to beginning: ["purple", "red", "green", "blue"]
colors.shift(); // Remove from beginning: ["red", "green", "blue"]
// Finding elements
console.log(colors.indexOf("green")); // 1
console.log(colors.includes("blue")); // true
// Transforming arrays
console.log(colors.join(", ")); // "red, green, blue"
console.log(colors.slice(1, 3)); // ["green", "blue"]
console.log(colors.concat(["yellow", "orange"])); // ["red", "green", "blue", "yellow", "orange"]
// Iterating over arrays
colors.forEach(function(color) {
console.log(color);
});
// Transformative iterations
let uppercase = colors.map(function(color) {
return color.toUpperCase();
});
console.log(uppercase); // ["RED", "GREEN", "BLUE"]
let longColors = colors.filter(function(color) {
return color.length > 3;
});
console.log(longColors); // ["green", "blue"]
Function 🧩
Functions are reusable blocks of code that perform specific tasks.
Function Declaration
// Basic function declaration
function greet(name) {
return `Hello, ${name}!`;
}
// Calling the function
let greeting = greet("Sarah");
console.log(greeting); // "Hello, Sarah!"
// Function with default parameters
function greetWithDefault(name = "Guest") {
return `Hello, ${name}!`;
}
console.log(greetWithDefault()); // "Hello, Guest!"
console.log(greetWithDefault("John")); // "Hello, John!"
Function Expression
// Function expression (anonymous)
const add = function(a, b) {
return a + b;
};
console.log(add(5, 3)); // 8
// Named function expression
const subtract = function subtractFn(a, b) {
return a - b;
};
console.log(subtract(10, 4)); // 6
Arrow Functions
// Arrow function (shorter syntax)
const multiply = (a, b) => a * b;
console.log(multiply(4, 5)); // 20
// Arrow function with block body
const divide = (a, b) => {
if (b === 0) {
return "Cannot divide by zero";
}
return a / b;
};
console.log(divide(10, 2)); // 5
console.log(divide(10, 0)); // "Cannot divide by zero"
// Arrow functions and 'this'
// Regular functions create their own 'this'
// Arrow functions inherit 'this' from surrounding scope
const person = {
name: "John",
regularMethod: function() {
return `Hello, my name is ${this.name}`;
},
arrowMethod: () => {
return `Name is ${this.name}`; // 'this' refers to outer scope, not person
}
};
console.log(person.regularMethod()); // "Hello, my name is John"
console.log(person.arrowMethod()); // "Name is undefined"
Function Parameters and Arguments
// Multiple parameters
function createUser(name, age, isAdmin) {
return {
name: name,
age: age,
isAdmin: isAdmin
};
}
const user1 = createUser("Alice", 28, false);
// Rest parameters
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
// Arguments object (older method)
function logArguments() {
console.log(arguments);
for (let i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
logArguments("a", "b", "c"); // Logs "a", "b", "c"
Function Scope and Closures
// Closures: functions remember their creation environment
function createCounter() {
let count = 0; // This variable is "closed over"
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
// Another counter instance has its own separate count
const counter2 = createCounter();
console.log(counter2()); // 1
Immediately Invoked Function Expressions (IIFE)
// Function that executes immediately
(function() {
const privateVar = "I'm private";
console.log("IIFE executed!");
})();
// IIFE with parameters
(function(name) {
console.log(`Hello, ${name}!`);
})("JavaScript");
Higher-Order Functions
// Function that takes another function as a parameter
function doTwice(func, value) {
return func(func(value));
}
function addFive(num) {
return num + 5;
}
console.log(doTwice(addFive, 10)); // 20 (first adds 5 to get 15, then adds 5 again)
// Function that returns a function
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
If/else 🔀
Conditional statements execute different code based on different conditions.
Basic if Statement
// Basic if statement
let temperature = 75;
if (temperature > 70) {
console.log("It's warm outside!");
}
// Nothing happens if the condition is false
temperature = 65;
if (temperature > 70) {
console.log("This won't be logged");
}
If-else Statement
// if-else statement
let hour = 14;
if (hour < 12) {
console.log("Good morning!");
} else {
console.log("Good afternoon or evening!");
}
If-else-if Ladder
// if-else-if ladder for multiple conditions
let score = 85;
if (score >= 90) {
console.log("Grade: A");
} else if (score >= 80) {
console.log("Grade: B");
} else if (score >= 70) {
console.log("Grade: C");
} else if (score >= 60) {
console.log("Grade: D");
} else {
console.log("Grade: F");
}
Logical Operators
// Logical AND (&&)
let age = 25;
let hasLicense = true;
if (age >= 18 && hasLicense) {
console.log("You can drive");
}
// Logical OR (||)
let isWeekend = false;
let isHoliday = true;
if (isWeekend || isHoliday) {
console.log("No work today!");
}
// Logical NOT (!)
let isLoggedIn = false;
if (!isLoggedIn) {
console.log("Please log in to continue");
}
// Combining logical operators
let age2 = 20;
let hasParentalConsent = false;
let isEmergency = true;
if ((age2 >= 18 || hasParentalConsent) && !isEmergency) {
console.log("Standard procedure");
} else {
console.log("Special handling required");
}
Ternary Operator
// Ternary operator as shorthand for if-else
let age3 = 20;
let message = age3 >= 18 ? "You are an adult" : "You are a minor";
console.log(message); // "You are an adult"
// Nested ternary (use sparingly for readability)
let temperature2 = 75;
let weather =
temperature2 < 32 ? "freezing" :
temperature2 < 50 ? "cold" :
temperature2 < 70 ? "mild" :
temperature2 < 85 ? "warm" : "hot";
console.log(weather); // "warm"
Switch Statement
// Switch statement for multiple cases
let day = "Monday";
switch (day) {
case "Monday":
console.log("Start of the work week");
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
console.log("Midweek");
break;
case "Friday":
console.log("End of the work week");
break;
case "Saturday":
case "Sunday":
console.log("Weekend");
break;
default:
console.log("Invalid day");
}
Truthy and Falsy Values
In JavaScript, values are evaluated as either "truthy" or "falsy" in boolean contexts:
// Falsy values
if (false) {} // doesn't execute
if (0) {} // doesn't execute
if ("") {} // doesn't execute
if (null) {} // doesn't execute
if (undefined) {} // doesn't execute
if (NaN) {} // doesn't execute
// Truthy values
if (true) { console.log("Executes"); }
if (1) { console.log("Executes"); }
if ("hello") { console.log("Executes"); }
if ([]) { console.log("Executes"); } // Empty array is truthy
if ({}) { console.log("Executes"); } // Empty object is truthy
if (function(){}) { console.log("Executes"); } // Functions are truthy
// This pattern is common for providing default values
let userInput = "";
let displayName = userInput || "Guest";
console.log(displayName); // "Guest" (because userInput is falsy)
// Nullish coalescing operator (??) only considers null and undefined as falsy
let count = 0;
let displayCount = count ?? "No count";
console.log(displayCount); // 0 (because count is 0, not null or undefined)
Practical Examples
Let's see some practical applications of conditionals:
// Form validation
function validateForm(username, password) {
if (!username) {
return "Username is required";
}
if (username.length < 3) {
return "Username must be at least 3 characters";
}
if (!password) {
return "Password is required";
}
if (password.length < 8) {
return "Password must be at least 8 characters";
}
return "Form is valid";
}
console.log(validateForm("", "password123")); // "Username is required"
console.log(validateForm("jo", "password123")); // "Username must be at least 3 characters"
console.log(validateForm("john", "")); // "Password is required"
console.log(validateForm("john", "pass")); // "Password must be at least 8 characters"
console.log(validateForm("john", "password123")); // "Form is valid"
// Toggle functionality
let lightIsOn = false;
function toggleLight() {
lightIsOn = !lightIsOn;
return lightIsOn ? "Light is now ON" : "Light is now OFF";
}
console.log(toggleLight()); // "Light is now ON"
console.log(toggleLight()); // "Light is now OFF"
// User permission checking
function checkAccess(user) {
if (!user) {
return "Please log in";
}
if (user.isAdmin) {
return "Full access granted";
} else if (user.isEditor) {
return "Editor access granted";
} else if (user.isSubscriber) {
return "Subscriber access granted";
} else {
return "Basic access granted";
}
}
console.log(checkAccess(null)); // "Please log in"
console.log(checkAccess({name: "John", isAdmin: true})); // "Full access granted"
console.log(checkAccess({name: "Sarah", isEditor: true})); // "Editor access granted"
console.log(checkAccess({name: "Guest"})); // "Basic access granted"
Putting It All Together 🧩
Let's combine these concepts to create a simple todo list application:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Todo List</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
h1 {
text-align: center;
}
.todo-container {
margin-top: 20px;
}
.todo-header {
display: flex;
margin-bottom: 10px;
}
#todoInput {
flex: 1;
padding: 8px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px 0 0 4px;
}
#addButton {
padding: 8px 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 0 4px 4px 0;
cursor: pointer;
}
#addButton:hover {
background-color: #45a049;
}
ul {
list-style-type: none;
padding: 0;
}
li {
padding: 10px;
background-color: #f9f9f9;
margin-bottom: 5px;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}
li button {
background-color: #f44336;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
li button:hover {
background-color: #d32f2f;
}
.completed {
text-decoration: line-through;
opacity: 0.6;
}
</style>
</head>
<body>
<h1>Simple Todo List</h1>
<div class="todo-container">
<div class="todo-header">
<input type="text" id="todoInput" placeholder="Add a new task...">
<button id="addButton">Add</button>
</div>
<ul id="todoList">
<!-- Todo items will go here -->
</ul>
</div>
<script>
// Variables to store DOM elements
const todoInput = document.getElementById('todoInput');
const addButton = document.getElementById('addButton');
const todoList = document.getElementById('todoList');
// Array to store todo items
let todos = [];
// Function to add a new todo
function addTodo() {
const todoText = todoInput.value.trim();
// If input is empty, don't add anything
if (todoText === '') {
return;
}
// Create a new todo object
const todo = {
id: Date.now(), // Using timestamp as a unique ID
text: todoText,
completed: false
};
// Add to array
todos.push(todo);
// Reset input
todoInput.value = '';
// Update the UI
renderTodos();
}
// Function to toggle a todo's completed status
function toggleTodo(id) {
// Find the todo in the array
todos = todos.map(todo => {
if (todo.id === id) {
// Toggle completed status
return { ...todo, completed: !todo.completed };
}
return todo;
});
// Update the UI
renderTodos();
}
// Function to delete a todo
function deleteTodo(id) {
// Filter out the todo with the given id
todos = todos.filter(todo => todo.id !== id);
// Update the UI
renderTodos();
}
// Function to render todos to the DOM
function renderTodos() {
// Clear the list
todoList.innerHTML = '';
// If there are no todos, show a message
if (todos.length === 0) {
const emptyMessage = document.createElement('p');
emptyMessage.textContent = 'No tasks yet. Add one above!';
todoList.appendChild(emptyMessage);
return;
}
// Loop through todos and create list items
todos.forEach(todo => {
const li = document.createElement('li');
// Create a span for the text
const span = document.createElement('span');
span.textContent = todo.text;
// If completed, add the class
if (todo.completed) {
span.classList.add('completed');
}
// Add click event to toggle completed status
span.addEventListener('click', () => toggleTodo(todo.id));
// Create delete button
const deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';
deleteButton.addEventListener('click', () => deleteTodo(todo.id));
// Add elements to list item
li.appendChild(span);
li.appendChild(deleteButton);
// Add list item to the list
todoList.appendChild(li);
});
}
// Add event listeners
addButton.addEventListener('click', addTodo);
todoInput.addEventListener('keypress', function(e) {
// Add todo when Enter key is pressed
if (e.key === 'Enter') {
addTodo();
}
});
// Initial render
renderTodos();
</script>
</body>
</html>
This example demonstrates all the concepts we've covered:
- Variables for storing data
- Different types (strings, numbers, booleans, objects, arrays)
- Functions for organizing code
- Conditional statements for making decisions
Advanced JavaScript Concepts
Now that you've learned the basics, here are some more advanced JavaScript concepts to explore:
Asynchronous JavaScript
// Callbacks
function fetchData(callback) {
setTimeout(() => {
callback("Data received");
}, 1000);
}
fetchData(function(data) {
console.log(data); // "Data received" after 1 second
});
// Promises
function fetchDataPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
// If there was an error: reject("An error occurred");
}, 1000);
});
}
fetchDataPromise()
.then(data => console.log(data))
.catch(error => console.error(error));
// Async/await
async function getData() {
try {
const data = await fetchDataPromise();
console.log(data);
} catch (error) {
console.error(error);
}
}
getData();
DOM Manipulation
// Selecting elements
const element = document.getElementById('myId');
const elements = document.querySelectorAll('.myClass');
// Changing content
element.textContent = "New text";
element.innerHTML = "<strong>Bold text</strong>";
// Changing styles
element.style.color = "blue";
element.style.backgroundColor = "yellow";
// Adding/removing classes
element.classList.add('highlight');
element.classList.remove('hidden');
element.classList.toggle('active');
// Creating elements
const newElement = document.createElement('div');
newElement.textContent = "New element";
document.body.appendChild(newElement);
// Event listeners
element.addEventListener('click', function(event) {
console.log("Element clicked!", event);
});
Practice exercises:
- Create a calculator:
- Build a simple calculator with functions for add, subtract, multiply, and divide
- Add a memory feature to store and recall values
- Use conditional statements to handle division by zero
- Build a form validator:
- Create functions to validate email, password, and phone number
- Use regular expressions for pattern matching
- Provide appropriate error messages for invalid inputs
- Implement a toggle system:
- Create a theme switcher that toggles between light and dark mode
- Store the user's preference in a variable
- Use conditional rendering to apply the appropriate styles
- Create a quiz application:
- Store questions and answers in an array of objects
- Use functions to check answers and calculate score
- Use conditionals to determine if the answer is correct
Pro Tip: JavaScript is a powerful language with many features. Don't try to memorize everything—instead, understand the core concepts and practice them regularly. Learning by building small projects is one of the most effective ways to improve your JavaScript skills.
What you've learned:
- How to create and work with variables and data types
- Writing and using functions for code organization and reuse
- Using conditional statements to make decisions in your code
- Combining these concepts to build interactive web applications
Coming up next: In Chapter 6, we'll explore the command line terminal and learn essential commands for web development workflows.

