JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
81: Handling Events
I once worked with a junior developer who spent nearly an entire afternoon debugging a "broken" submit button. The HTML was perfect, the CSS was polished, and the function to handle the data was written and tested in isolation. But when he clicked the button, nothing happened. He had written button.addEventListener('click', handleSubmit());. By adding those parentheses at the end of the function name, he wasn't telling JavaScript to run the function when the click happened; he was telling it to run the function immediately when the page loaded and then assign the result of that function to the click event. Since the function returned nothing, the button did nothing. It's a classic mistake, and it's exactly why understanding how we "wire" events is so critical.
Connecting Actions to Logic
In JavaScript, we don't want our code to just run from top to bottom and then stop. We want it to wait for the user to do something. This is where event listeners come in. While you might see some older tutorials using onclick attributes directly in the HTML, I strongly recommend avoiding that. It mixes your logic with your markup and makes your code a nightmare to maintain.
The modern standard is addEventListener(). This method takes two primary arguments: the name of the event you're listening for (like 'click', 'submit', or 'keydown') and the function you want to execute when that event occurs. Notice that we pass the function by name, without parentheses, so that JavaScript can call it later.
const likeButton = document.querySelector('#like-btn');
function toggleLike() {
likeButton.textContent = '❤️ Liked!';
likeButton.classList.add('active');
}
// We pass the reference to the function, not the result of calling it
likeButton.addEventListener('click', toggleLike);
Taming the Event Object
Most of the time, you don't just want to know that something happened; you want to know how it happened. Was the Shift key held down during the click? Which specific item in a long list was clicked? JavaScript handles this by automatically passing an "event object" as the first argument to your handler function.
I often see people name this parameter e or event. This object is a goldmine of information. One of the most important methods you'll use within this object is preventDefault(). If you've ever clicked a submit button in a form and noticed the page refreshed instantly—wiping out all your data—that's the browser's default behavior. To stop that and handle the submission via JavaScript (like sending it to an API), you have to explicitly tell the browser to stand down.
const registrationForm = document.querySelector('#reg-form');
registrationForm.addEventListener('submit', (e) => {
e.preventDefault(); // Stops the page from reloading
console.log('Form submitted without a page refresh!');
// Now you can validate the data and send it via fetch()
});
Beyond clicks and submits, you can listen for almost anything. 'input' is fantastic for real-time validation as a user types, and 'mouseenter' or 'mouseleave' can handle those subtle UI hover effects that CSS alone can't quite manage. Just remember: for every listener you add, make sure you actually need it. Overloading a page with hundreds of listeners can occasionally lead to performance lag, though for most projects, the bottleneck is usually elsewhere.
📋 Practical Task
Build a Real-time Character Counter for a Comment Box
Create a simple interface consisting of a <textarea> and a small <span> that displays the current character count (e.g., "0 / 280").
- Write a JavaScript function that reads the current length of the textarea's value.
- Use the
'input'event listener to trigger this function every time the user types, deletes, or pastes text. - Update the text content of the span to reflect the current count.
- Bonus: Change the color of the count text to red once the user exceeds 280 characters.
There are no comments for now.