Objects, Scope, Event Handling, and Validation Forms
You need JavaScript fundamentals (Unit 5): variables, data types, conditionals, loops, and functions. If if/else, for, and function syntax feel unfamiliar, review Unit 5 first. You'll also need basic HTML forms (U3) and CSS selectors (U4).
JavaScript treats almost everything as an Object. An object is a collection of key-value pairs.
String: Manipulated via methods like .length, .toUpperCase().Number: Handles integers and floats. Parsed via parseInt().Boolean: Represents logical true or false.Array: A special type of object used to store ordered lists. (e.g., let arr = [1, 2, 3];).let/const). They are destroyed from memory once the block finishes executing.
let globalVar = "University";
function processData() {
let localVar = "Student";
console.log(globalVar); // Works!
console.log(localVar); // Works!
}
console.log(localVar); // ERROR!
Arrays are the most commonly used data structure in JavaScript. The Array prototype provides powerful methods for data transformation.
Enter a JavaScript expression below and click Run to see the result. Try these examples:
[1,2,3].map(x => x * 2)[5,2,8,1].sort()"hello world".toUpperCase()(3.14159).toFixed(2)Strings and Numbers come with built-in methods accessible via the dot operator.
| Category | Method | Description | Example |
|---|---|---|---|
| String | .length | Character count | "hello".length → 5 |
| .toUpperCase() | Convert to uppercase | "hi".toUpperCase() → "HI" | |
| .toLowerCase() | Convert to lowercase | "HI".toLowerCase() → "hi" | |
| .trim() | Remove whitespace | " a ".trim() → "a" | |
| .split() | Split into array | "a,b".split(",") → ["a","b"] | |
| .replace() | Replace substring | "a b".replace(" ","-") → "a-b" | |
| Number | parseInt() | String → integer | parseInt("42") → 42 |
| parseFloat() | String → float | parseFloat("3.14") → 3.14 | |
| .toFixed() | Format decimal places | (3.14159).toFixed(2) → "3.14" | |
| isNaN() | Check if not-a-number | isNaN("abc") → true |
When an event fires on a nested element, it travels through three phases:
window down to the target element.window.By default, event listeners fire during the bubbling phase. To listen during capturing, pass { capture: true } as the third argument to addEventListener().
Click the Target button below to see event propagation in action:
// Capturing phase listeners (third argument: true)
outer.addEventListener('click', () => {
logEvent('CAPTURING: Outer div caught event on way DOWN', 'capture');
}, true);
inner.addEventListener('click', () => {
logEvent('CAPTURING: Inner div caught event on way DOWN', 'capture');
}, true);
// Target phase listener (default: bubbling phase)
target.addEventListener('click', () => {
logEvent('TARGET: The button itself received the click', 'target');
});
// Bubbling phase listeners (third argument omitted / false)
inner.addEventListener('click', () => {
logEvent('BUBBLING: Inner div caught event on way UP', 'bubble');
});
outer.addEventListener('click', () => {
logEvent('BUBBLING: Outer div caught event on way UP', 'bubble');
});Events are categorized by the type of user interaction. Here are the most commonly used ones:
onclick (mouse click), onsubmit (form submission), oninput (typing).try block. If it fails, the engine throws control to the catch block, allowing us to handle the error gracefully.Click the button below to trigger the onclick event and spawn the responsive modal DOM node.
<!-- Pattern attribute for inline validation -->
<input type="text" pattern="[A-Za-z]{3,}" title="At least 3 letters">
// JavaScript validation with checkValidity() / reportValidity()
function validateForm() {
const name = document.getElementById('stuName').value.trim();
if (name.length < 3) {
document.getElementById('nameErr').style.display = 'block';
return false;
}
// HTML5 validation API
const input = document.getElementById('stuReg');
if (!input.checkValidity()) {
input.reportValidity();
return false;
}
return true;
}Instead of attaching a listener to every element, attach ONE listener to a parent and use e.target to determine which child was clicked. This works because events bubble up from target to parent:
document.getElementById("list").addEventListener("click", function(e) {
if (e.target.tagName === "LI") {
console.log("Clicked:", e.target.textContent);
}
});
Benefits: works for dynamically added elements, uses less memory, and requires only one listener instead of hundreds. This pattern is essential for large lists, tables, and menus.
| Feature | localStorage | sessionStorage | Cookies | IndexedDB |
|---|---|---|---|---|
| Capacity | 5-10 MB | 5-10 MB | 4 KB | Unlimited (250 MB+) |
| Persistence | Until cleared | Tab close | Per expiry | Until cleared |
| Sent to server | No | No | Yes (every request) | No |
| Data type | String only | String only | String only | Any structured data |
| Sync/Async | Sync | Sync | Sync | Async (promise-based) |
| Use case | Preferences, cache | Form drafts | Auth tokens | Offline apps, blobs |
For most course data (quiz progress, theme, unit completion), localStorage is the right choice. Use IndexedDB when storing large datasets or binary data. Cookies should only be used for server-auth tokens.