1. Learning Objective
By the end of this lesson you will:
- Understand what a function is and why we need them
- Create functions using function declarations, function expressions, and arrow functions
- Pass data into functions with parameters and get data back with return values
- Understand scope β where variables live and die
- Wire up functions to user actions using addEventListener
- Use the event object to know what the user did
- Handle multiple event types: click, input, keydown, submit
Why This Matters
Every button click, every form submission, every dropdown menu, every search bar on every website you've ever used β they all work because of functions and events. In React, every component is literally a function. In Next.js, every page is a function. In Node.js/Express, every API route handler is a function. This lesson is the single most important JavaScript lesson in your entire journey.
2. Prerequisites β Quick Revision
Before we start, let's make sure the Lesson 9 foundations are solid:
| Concept | What You Should Know |
|---|---|
let / const | const for values that don't change, let for values that do |
| Data Types | string, number, boolean, null, undefined |
| Template Literals | Backtick strings with ${variable} interpolation |
console.log() | Prints values to the DevTools Console for debugging |
document.getElementById() | Finds an HTML element by its id attribute |
.innerHTML | Sets or gets the HTML content inside an element |
If any of these feel fuzzy, review the JavaScript Foundations reference before continuing.
3. What Is a Function? β The Mental Model
3.1 The Real-Life Analogy
Think of a function like a recipe card in a kitchen:
- The recipe card has a name β "Make Chai"
- It lists ingredients you need (inputs) β water, tea leaves, milk, sugar
- It has step-by-step instructions (the body) β boil water, add leaves, etc.
- It produces a result (the return value) β a cup of chai
You write the recipe once. But you can use it as many times as you want β every morning, for every guest. That's exactly what a function does: you write the code once, and call it whenever you need it.
Figure 1 β A function has a name, takes inputs (parameters), runs instructions (body), and gives back an output (return value).
4. Creating Functions β Three Ways
4.1 Function Declaration (The Classic Way)
This is the most common and beginner-friendly way to create a function:
function greet(name) {
const message = `Hello, ${name}! Welcome.`;
return message;
}
// Calling the function
const result = greet("Altamash");
console.log(result); // "Hello, Altamash! Welcome."
function is the keyword that tells JavaScript "I'm creating a recipe." greet is the name of the recipe. name is a parameter β a placeholder for the actual value you'll pass in later. The { opens the body.
${name} gets replaced with whatever value was passed in.
return sends the value back to whoever called the function. Without return, the function gives back undefined.
"Altamash" is the argument β the actual value that replaces the name parameter. The returned value gets stored in result.
β’ Parameter = the variable name in the function definition:
function greet(name)
β’ Argument = the actual value you pass when calling:
greet("Altamash")
Think of it this way: the parameter is the parking spot, the argument is the car you park in it.
4.2 Function Expression (Storing a Function in a Variable)
A function can also be stored in a variable, just like a number or a string:
const greet = function(name) {
return `Hello, ${name}!`;
};
console.log(greet("Altamash")); // "Hello, Altamash!"
Notice: the function has no name after the function keyword. It's "anonymous" β it gets its name from the variable. The semicolon at the end is required because this is a variable assignment, not a declaration.
4.3 Arrow Function (The Modern Way) β
Arrow functions were introduced in ES6 (2015) and are the preferred way to write short functions in modern JavaScript, React, and Next.js:
// Full syntax
const greet = (name) => {
return `Hello, ${name}!`;
};
// Shorthand: if the body is a single expression, skip { } and return
const greetShort = (name) => `Hello, ${name}!`;
// If only one parameter, skip the parentheses too
const greetShorter = name => `Hello, ${name}!`;
console.log(greetShorter("Altamash")); // "Hello, Altamash!"
=> is called the fat arrow. It replaces the function keyword. Read it as: "takes name, then does this."
{ } and the return keyword. The expression's value is automatically returned. This is called an implicit return.
4.4 Comparison: Three Ways to Write Functions
| Feature | Declaration | Expression | Arrow β |
|---|---|---|---|
| Syntax | function name() {} |
const name = function() {}; |
const name = () => {}; |
| Hoisted? | β Yes β can call before it's defined | β No | β No |
Has own this? |
β Yes | β Yes | β No β inherits from parent |
| Implicit return? | β No | β No | β Yes (single-expression body) |
| Best for | Top-level named functions | Callbacks (older code) | Callbacks, React components, event handlers |
5. Parameters, Default Values, and Return
5.1 Multiple Parameters
const calculateTotal = (price, quantity, taxRate) => {
const subtotal = price * quantity;
const tax = subtotal * taxRate;
return subtotal + tax;
};
const total = calculateTotal(499, 2, 0.18);
console.log(total); // 1177.64
5.2 Default Parameters
What if someone calls your function but forgets to pass a value? You can provide a fallback:
const greet = (name = "stranger") => `Hello, ${name}!`;
console.log(greet("Altamash")); // "Hello, Altamash!"
console.log(greet()); // "Hello, stranger!"
The = "stranger" after the parameter means: "If no argument is passed, use "stranger" as the default." The default is only used when the argument is undefined (which is what happens when you don't pass anything).
5.3 Return β The Function's Output
Three critical rules about return:
returnimmediately stops the function β any code after it is unreachable- A function without
returngives backundefined - Never put a newline between
returnand the value (JavaScript auto-inserts a semicolon!)
The Newline Trap
function getPrice() {
return // β JavaScript inserts a semicolon HERE!
499; // β This line is never reached
}
console.log(getPrice()); // undefined (not 499!)
function getPrice() {
return 499;
}
Why? JavaScript has a feature called Automatic Semicolon Insertion (ASI). If return is alone on a line, JS thinks the statement is return; (return undefined). This is a real-world production bug that has bitten professional developers.
6. Scope β Where Variables Live and Die
Scope means: "Where in the code can I access this variable?" Think of it like rooms in a house:
- Global scope = the living room. Everyone in the house can access things here.
- Function scope = a bedroom. Only the person inside that room can access what's in it. People in the living room can't see inside the bedroom.
const appName = "My Portfolio"; // GLOBAL β visible everywhere
function showWelcome() {
const greeting = "Welcome!"; // LOCAL β only visible inside this function
console.log(appName); // β
Can access global from inside function
console.log(greeting); // β
Can access own local variable
}
showWelcome();
console.log(appName); // β
Global β accessible here
console.log(greeting); // β ReferenceError! greeting is LOCAL to showWelcome
Scope Rule β Simple Version
- A function can see out (access variables from the scope where it was created)
- But the outside cannot see in (cannot access variables declared inside a function)
- This is like a one-way mirror: the function sees the world, but the world can't see inside the function
7. Visual Execution β The Call Stack
When JavaScript runs your code, it uses a call stack β a stack of "frames" that track which function is currently running. Think of it like a stack of plates:
function multiply(a, b) {
return a * b;
}
function calculateArea(width, height) {
const area = multiply(width, height);
return area;
}
const result = calculateArea(5, 10);
console.log(result); // 50
Here's how the call stack evolves, step by step:
Figure 2 β The call stack: functions are pushed on when called, popped off when they return. Last in, first out (LIFO).
What Happens in Memory
- JavaScript starts running your script β it creates a Global Execution Context and pushes it onto the call stack
- When it hits
calculateArea(5, 10), it creates a new execution context for that function, with its own local variables (width = 5,height = 10), and pushes it onto the stack - Inside
calculateArea, it hitsmultiply(width, height)β another execution context is created and pushed multiplyreturns50β its context is popped off the stackcalculateAreareturns50β its context is popped off- We're back in the global context.
resultis now50.
7.1 Try It Yourself
8. Events β Making Pages React to Users
8.1 What Is an Event?
An event is anything that happens in the browser that you can respond to:
- The user clicks a button β
"click"event - The user types in an input field β
"input"event - The user presses a key β
"keydown"event - The user submits a form β
"submit"event - The user hovers over an element β
"mouseenter"event - The page finishes loading β
"DOMContentLoaded"event
The real-life analogy: events are like a doorbell. The doorbell itself does nothing until someone rings it. You set up a function (the "handler") that should run when the doorbell rings. The browser is the house β it watches for rings and calls your handler when one happens.
8.2 addEventListener β The Right Way
<button id="greet-btn">Click me!</button>
<p id="output"></p>
// Step 1: Find the elements
const button = document.getElementById("greet-btn");
const output = document.getElementById("output");
// Step 2: Define what should happen when clicked
const handleClick = () => {
output.textContent = "Hello! You clicked the button! π";
};
// Step 3: Wire the function to the event
button.addEventListener("click", handleClick);
button fires a "click" event, run the handleClick function."
β’ First argument: the event type (a string β
"click", "input", "keydown", etc.)
β’ Second argument: the function to call (the event handler / callback)
Notice: We pass
handleClick β NOT handleClick(). The parentheses would immediately call the function instead of waiting for the click!
Calling Instead of Passing
button.addEventListener("click", handleClick()); // β () calls it NOW, not on click!
button.addEventListener("click", handleClick); // β No () β we're PASSING the function
This is the #1 beginner mistake with events. Remember: you're giving the browser a reference to the function (like handing someone a recipe card), not executing it yourself.
8.3 Inline Arrow Functions in addEventListener
You don't always need a separate named function. For short handlers, write the arrow function directly:
button.addEventListener("click", () => {
output.textContent = "Clicked! π";
});
8.4 The Event Object β Know What Happened
Every time an event fires, the browser automatically passes an event object to your handler function. This object contains details about the event:
button.addEventListener("click", (event) => {
console.log(event.type); // "click"
console.log(event.target); // the button element that was clicked
console.log(event.clientX); // X coordinate of the mouse pointer
});
| Property | What It Tells You | Example Value |
|---|---|---|
event.type | Which event fired | "click", "keydown" |
event.target | The element that triggered the event | The <button> element |
event.key | Which keyboard key was pressed (keydown events) | "Enter", "a" |
event.preventDefault() | Stops the browser's default behavior | Prevents form from reloading the page |
event.clientX / clientY | Mouse pointer position | 142, 305 |
The parameter name event is a convention β you can call it e or evt too. Most professionals use e for brevity.
8.5 Common Event Types β A Practical Reference
| Event | Fires When⦠| Use Case |
|---|---|---|
"click" | User clicks an element | Buttons, links, toggles |
"input" | User types/changes an input field value | Live search, character counters |
"change" | Input loses focus after being changed | Dropdown selects, checkboxes |
"keydown" | User presses a key down | Keyboard shortcuts, game controls |
"submit" | Form is submitted | Contact forms, login forms |
"mouseenter" | Mouse moves over an element | Hover effects, tooltips |
"mouseleave" | Mouse moves away from an element | Closing tooltips |
9. Real-World Example β Interactive Form
Let's combine functions and events to build something real: a form that reacts as the user types and prevents the default page reload on submit.
<form id="contact-form">
<label for="name-input">Name:</label>
<input type="text" id="name-input" placeholder="Your name">
<p id="live-preview"></p>
<button type="submit">Submit</button>
</form>
<p id="form-result"></p>
// 1. Find the elements
const form = document.getElementById("contact-form");
const nameInput = document.getElementById("name-input");
const preview = document.getElementById("live-preview");
const result = document.getElementById("form-result");
// 2. Live preview as user types
nameInput.addEventListener("input", (e) => {
const value = e.target.value;
preview.textContent = value
? `Hello, ${value}! π`
: "";
});
// 3. Handle form submission
form.addEventListener("submit", (e) => {
e.preventDefault(); // β CRUCIAL: stops page from reloading!
const name = nameInput.value.trim();
if (name === "") {
result.textContent = "Please enter your name!";
return; // exit early
}
result.textContent = `β
Form submitted! Welcome, ${name}!`;
nameInput.value = ""; // clear the input
preview.textContent = "";
});
Why e.preventDefault()?
By default, when a form is submitted, the browser reloads the entire page (or navigates to a new URL). This destroys all your JavaScript state. e.preventDefault() says: "Don't do the default thing. I'll handle it with JavaScript instead." This is used in every single React and Next.js form.
10. Common Mistakes β The Pitfall Gallery
Mistake 1: Forgetting return
const double = (n) => { n * 2; }; // β Returns undefined!
const double = (n) => { return n * 2; }; // β
Explicit return
const double = (n) => n * 2; // β
Implicit return (no braces)
If you use { } in an arrow function, you must write return explicitly.
Mistake 2: Shadowing Variables
let count = 0;
function increment() {
let count = 0; // β Creates a NEW local variable β doesn't change the outer one!
count++;
}
increment();
console.log(count); // Still 0!
If you declare a variable with the same name inside a function, it "shadows" (hides) the outer variable. Remove the let inside the function if you want to modify the outer variable.
Mistake 3: Using an Element Before It Exists
<head>
<script src="script.js"></script> <!-- β Runs before the HTML body loads -->
</head>
Fix: Put your <script> at the end of the body, or use the defer attribute: <script src="script.js" defer>.
11. Interview Perspective
What interviewers ask about functions & events
- "What is the difference between a parameter and an argument?"
Parameter = placeholder in the definition. Argument = actual value at call time. - "What is hoisting?"
Function declarations are "hoisted" β moved to the top of their scope before execution. You can call them before they appear in the code. Function expressions and arrow functions are NOT hoisted. - "What happens if you call a function that doesn't return anything?"
It returnsundefined. - "What is the difference between
addEventListenerandonclick?"addEventListenerlets you attach multiple handlers to the same event.onclickonly allows one β the latest one overwrites previous ones. Always useaddEventListener. - "What does
e.preventDefault()do?"
Stops the browser's default behavior for that event (e.g., form submission reloading the page, link navigation). - Tricky: "What does this code output?"
Answer: ReferenceError! Due to the Temporal Dead Zone (TDZ). Theconst x = 10; function test() { console.log(x); const x = 20; } test();const x = 20inside the function shadows the outerx, but it can't be used before its declaration line. This is a scope + hoisting trap.
12. Best Practices β How Professionals Write Functions
- Use arrow functions for callbacks and event handlers
- Use function declarations for top-level utility functions
- Name functions descriptively β
handleClick,calculateTotal,formatDate, notfn,doStuff,x - Keep functions small β a function should do ONE thing. If it's doing 5 things, split it into 5 functions
- Always use
addEventListenerβ never useonclickattributes in HTML - Always use
e.preventDefault()on form submit handlers - Prefer
constfor function expressions β prevents accidental reassignment - Use default parameters instead of checking for
undefinedmanually
13. Real-World Use Cases
Where You'll See This in the Wild
- React: Every React component is a function. Every
onClickhandler is a function passed to an event listener under the hood. - Next.js: Every page and API route is a function. Server Actions are async functions.
- Node.js / Express: Every route handler is a function:
app.get("/api/users", (req, res) => { ... }) - Array methods:
.map(),.filter(),.forEach()all take a function as an argument (this is called a callback) - Form validation: Every "Please enter a valid email" message is triggered by an event listener running a validation function
14. Knowledge Check β Quiz
Quiz: Functions & Events (6 Questions)
return immediately terminates function execution and specifies the value returned to the caller.return is the keyword. Without an explicit return, a JavaScript function gives back undefined.addEventListener take as its SECOND argument?"click"), second is the callback function to execute.()!return statement return undefined by default.return keyword, the result is always undefined.return keyword required)?const add = (a, b) => a + b; automatically returns a + b without braces or return.{ } perform an implicit return of the single expression inside.e.preventDefault() do inside a form submit handler?e.preventDefault() stops this default behavior so your JS can run.button.addEventListener("click", handleClick()) WRONG?handleClick() runs the function right away during registration. Omit () to pass the function reference!() invokes the function right away instead of passing it as a handler for future clicks. Omit ()!15. Retrieval Practice β Fill in the Blanks
Write from memory. Effortful recall is how knowledge moves into long-term memory.
16. Practice Questions (Easy β Hard)
Do NOT look at answers. Write the code yourself, run it, and verify.
- Write a function
squarethat takes a number and returns its square. Easy - Write an arrow function
isEventhat returnstrueif a number is even,falseotherwise. Easy - Write a function
greetUserwith a default parameter so thatgreetUser()returns"Hello, Guest!". Easy - Create a button in HTML. When clicked, it changes its own text to "Clicked!". Easy
- Create an input field and a paragraph. As the user types, the paragraph shows a live character count. Medium
- Write a function
maxthat takes two numbers and returns the larger one. Do NOT useMath.max. Medium - Create a "Toggle Dark Mode" button. Clicking it adds/removes a class
"dark"on the<body>tag. Medium - Write a function
factorialthat calculates the factorial of a number using a loop.factorial(5)should return120. Medium - Build a mini calculator: two input fields, four buttons (+, β, Γ, Γ·), and a result display. Each button calls a calculation function and updates the result. Hard
- Create a password input with a "Show/Hide" toggle button. When clicked, it switches the input type between
"password"and"text". Hard
17. Mini Project β Interactive Profile Card
π οΈ Build Challenge: Make Your Portfolio Card Interactive
Take the profile card you built in Lesson 9 (using the data β template β inject pattern) and upgrade it with functions and events:
- Create a function called
renderProfilethat takesname,focus, andskillsas parameters, builds the template literal HTML, and returns it. - Create a form with three input fields: Name, Focus, and Skills (comma-separated).
- Add a "Generate Card" button. When the form is submitted:
- Call
e.preventDefault() - Read the values from the input fields
- Call
renderProfile()with those values - Inject the returned HTML into the page using
.innerHTML
- Call
- Add live preview: As the user types in the "Name" field, show a live greeting above the form.
- Add validation: If the name is empty, show an error message instead of generating the card.
What This Project Teaches
- Functions with parameters and return values β
renderProfiletakes data in, produces HTML out - Event listeners β
"submit"on the form,"input"on the name field e.preventDefault()β stop the form from reloading- Reading user input β
inputElement.value - The data β template β inject pattern β reinforcing the React mental model
This is literally how React forms work, minus the JSX syntax. If you can build this, you understand the core pattern of 90% of web applications.
18. Lesson Summary
- A function is a reusable block of code with a name, parameters, a body, and a return value
- Three ways to create functions: declaration, expression, arrow function (use arrow for most things)
- Parameters are placeholders; arguments are the actual values you pass
- Default parameters provide fallback values when arguments are missing
returnsends a value back. Without it, you getundefined- Scope: functions can see out (access globals), but the outside cannot see in (local variables are private)
- Events are things that happen in the browser (click, input, submit, keydown)
addEventListeneris the right way to wire a function to an event- Pass the function by name (no parentheses):
addEventListener("click", handler) - The event object (
e) gives you details about what happened e.preventDefault()stops the browser's default action (essential for forms)
19. Quick Revision Notes (5-Minute Review)
Functions Cheat Sheet
// Declaration (hoisted)
function add(a, b) { return a + b; }
// Arrow (modern, preferred)
const add = (a, b) => a + b;
// Default parameter
const greet = (name = "Guest") => `Hi, ${name}`;
// Functions return undefined if no return keyword
Events Cheat Sheet
// Attach event
element.addEventListener("click", handler);
// Inline arrow
button.addEventListener("click", (e) => {
e.preventDefault();
console.log(e.target);
});
// Common events: click, input, submit, keydown, change
// NEVER use handleClick() with () in addEventListener!
20. Challenge β Combine Functions + Events + Lesson 9
Build a "Grade Calculator" page:
- Create a form with 5 input fields for subject marks (out of 100 each).
- Write a function
calculateAveragethat takes 5 numbers and returns the average. - Write a function
getGradethat takes an average and returns a letter grade (A+ for 90+, A for 80+, B for 70+, C for 60+, F otherwise). - When the form is submitted, calculate the average and grade, then display both on the page using template literals.
- Add live preview: as the user types marks, show the running total of entered subjects.
- Validate: all marks must be between 0 and 100. Show an error for invalid input.
This challenge tests: functions with parameters & return, arrow functions, addEventListener, e.preventDefault(), template literals, conditionals, and validation.
21. Comprehension Check β Answer These Before Moving On
- In your own words, what is the difference between defining a function and calling a function?
- Why do arrow functions NOT have their own
this? (Hint: think about what would happen inside an event handler inside an object method.) - If you write
addEventListener("click", myFunc())instead ofaddEventListener("click", myFunc), what happens and why? - What is the call stack, and why does JavaScript need it?
- Why do we always call
e.preventDefault()in form submit handlers?
Primary Sources: javascript.info: Functions is the best free deep-dive on function mechanics. MDN: Introduction to events is the authoritative reference for event handling.
Finished the build? Type /teach and tell me what you built. I'll review your functions, event handlers, and the form validation pattern. After this, we move on to control flow: conditionals, comparison operators, and logical operators β where your code starts making decisions.