Week 4: JavaScript Basics I

INFO 153A/253A - Front-End Web Architecture

UC Berkeley School of Information

September 15, 2024

Section 1: JavaScript Fundamentals Review

Solidifying Your Foundation

Building Confidence with Core Concepts

Variables • Arrays • Objects • Data Types

Variable Declaration Patterns

Quick Check: Who can tell me the three ways to declare variables in JavaScript?

Modern JavaScript Approach

// Preferred patterns
const userName = 'john_doe';        // Won't reassign
let currentScore = 0;               // Will increment
let isLoggedIn = false;             // Will toggle

// Naming conventions
const firstName = 'John';           // camelCase
const MAX_RETRIES = 3;             // UPPER_SNAKE for constants
const apiEndpoint = '/api/users';   // descriptive names

Why These Choices Matter

  • const by default: Prevents accidental reassignment
  • let when changing: Clear intent to modify
  • Avoid var: Function-scoped, causes confusion
  • camelCase: JavaScript convention
  • Descriptive names: Self-documenting code

Working with Arrays

Real World: Lists of data (skills, menu items, products) are stored as arrays

Array Creation & Access

// Common web development arrays
const skills = ['HTML', 'CSS', 'JavaScript', 'Git'];
const projects = ['Website', 'Calculator', 'Weather App'];

// Zero-based indexing
console.log(skills[0]);     // 'HTML'
console.log(skills.length); // 4

// Adding new skills as you learn
skills.push('React');
skills.push('Node.js');

console.log(skills); 
// ['HTML', 'CSS', 'JavaScript', 'Git', 'React', 'Node.js']

Practical Array Methods

// Finding specific skills
const hasJavaScript = skills.includes('JavaScript'); // true
const reactIndex = skills.indexOf('React');          // 4

// Creating filtered lists
const frontendSkills = skills.filter(skill => 
    ['HTML', 'CSS', 'JavaScript', 'React'].includes(skill)
);

// Displaying skills on webpage
const skillsHTML = skills.map(skill => 
    `${skill}`
).join('');

console.log(skillsHTML); // HTML markup for skills

Objects and the const Confusion

Common Misconception: "const means the object can't change"

const Objects Are Mutable

const profile = {
    name: 'Your Name',
    skills: ['HTML', 'CSS'],
    projects: [],
    theme: 'light'
};

// ✅ These work - modifying properties
profile.skills.push('JavaScript');
profile.theme = 'dark';
profile.projects.push({
    title: 'My Website',
    tech: ['HTML', 'CSS', 'JavaScript']
});

// ❌ This fails - reassigning the variable
// profile = {}; // TypeError!

Real-World Object Patterns

// Settings management object
const userSettings = {
    name: '',
    email: '',
    preferences: {
        theme: 'light',
        animations: true,
        language: 'en'
    },
    
    updatePreference: function(key, value) {
        this.preferences[key] = value;
        console.log(`Updated ${key} to ${value}`);
    },
    
    getTheme: function() {
        return this.preferences.theme;
    }
};

// Application state management
const appState = {
    currentUser: null,
    isLoggedIn: false,
    dataLoaded: false,
    
    setUser: function(user) {
        this.currentUser = user;
        this.isLoggedIn = true;
        console.log(`Welcome ${user.name}!`);
    },
    
    logout: function() {
        this.currentUser = null;
        this.isLoggedIn = false;
        console.log('User logged out');
    }
};

Data Types in Action

Primitives vs References

// Primitives - stored by value
let score1 = 100;
let score2 = score1;    // Copies the value
score1 = 200;
console.log(score2);    // Still 100

// References - stored by reference
let user1 = { name: 'John', score: 100 };
let user2 = user1;      // Copies the reference
user1.score = 200;
console.log(user2.score); // Now 200!

Real Portfolio Implications

// This creates problems...
const defaultProject = {
    title: '',
    completed: false,
    tech: []
};

const project1 = defaultProject;
const project2 = defaultProject;

project1.title = 'Calculator';
console.log(project2.title); // 'Calculator' - Oops!

// Better approach - create new objects
const createProject = () => ({
    title: '',
    completed: false,
    tech: []
});

const project1 = createProject();
const project2 = createProject(); // Independent objects

Debugging Tip: Unexpected object behavior usually means you're sharing references

Knowledge Check & Questions

Interactive Review: Let's test your understanding before moving forward

Quick Challenges

  1. Create a const array of your skills
  2. Add a new skill using a method
  3. Create an object representing yourself
  4. Update a property in that object
  5. Explain why #4 works with const

Common Questions

  • Q: When should I use let vs const?
  • Q: Why avoid var completely?
  • Q: How do I copy an object safely?
  • Q: What's the difference between == and ===?
  • Q: Why are arrays objects in JavaScript?

Section 2: HTML Forms Deep Dive

Building Interactive User Interfaces

From Static to Interactive

Form Structure • Input Types • Validation • Processing

Real-World Application: Every professional website needs user input - contact forms, login, search, etc.

The Purpose and Power of Forms

Think Beyond Contact Forms: Login, search, e-commerce, surveys, file uploads, settings...

Forms Enable User Interaction

  • Communication: Contact forms, feedback
  • Authentication: Login, registration
  • Commerce: Checkout, product orders
  • Content: Blog posts, comments
  • Settings: User preferences
  • Search: Finding information

HTML vs JavaScript Roles

HTML Forms Provide:

  • Structure and semantics
  • Built-in browser validation
  • Accessibility features
  • Mobile keyboard optimization

HTML Cannot:

  • Process or store data
  • Send emails or messages
  • Perform complex validation
  • Create dynamic interactions

Form Structure and Attributes

Best Practice: Start with semantic HTML, enhance with JavaScript

Essential Form Elements

<form action="/contact" method="POST" novalidate>
    <fieldset>
        <legend>Contact Information</legend>
        
        <label for="name">Full Name *</label>
        <input type="text" id="name" name="name" required
               placeholder="Enter your full name">
        
        <label for="email">Email Address *</label>
        <input type="email" id="email" name="email" required
               placeholder="your@email.com">
    </fieldset>
    
    <button type="submit">Send Message</button>
</form>

Understanding the Attributes

  • action: Where to send form data
  • method: GET (visible) or POST (hidden)
  • novalidate: Use JavaScript validation instead
  • fieldset/legend: Grouping related fields
  • label for: Must match input id
  • name: Key for form data
  • required: HTML5 validation
  • placeholder: Helpful hints

Accessibility: Proper labels are essential for screen readers

Input Types and Their Superpowers

Mobile-First Benefit: Each input type triggers the appropriate mobile keyboard

Text-Based Inputs

<!-- Basic text input -->
<input type="text" placeholder="Full name">

<!-- Email with built-in validation -->
<input type="email" placeholder="user@example.com">

<!-- Secure password input -->
<input type="password" placeholder="Password">

<!-- Numbers with spin controls -->
<input type="number" min="0" max="100" step="1">

<!-- Phone numbers -->
<input type="tel" placeholder="(555) 123-4567">

<!-- URLs with protocol validation -->
<input type="url" placeholder="https://yoursite.com">

<!-- Multi-line text -->
<textarea rows="4" placeholder="Your message"></textarea>

Selection and Specialized Inputs

<!-- Dropdown selection -->
<select name="subject">
    <option value="">Choose subject...</option>
    <option value="general">General Question</option>
    <option value="project">Project Discussion</option>
</select>

<!-- Multiple options allowed -->
<input type="checkbox" id="newsletter" value="yes">
<label for="newsletter">Subscribe to newsletter</label>

<!-- Single selection from group -->
<input type="radio" id="contact-email" name="contact" value="email">
<label for="contact-email">Email</label>
<input type="radio" id="contact-phone" name="contact" value="phone">
<label for="contact-phone">Phone</label>

<!-- File uploads -->
<input type="file" accept=".pdf,.doc,.docx" multiple>

<!-- Date selection -->
<input type="date" min="2024-01-01">

Form Processing Reality Check

Critical Understanding: HTML forms can't send emails or save data by themselves

What HTML Forms Can't Do

  • Send emails
  • Save to databases
  • Process payments
  • Upload to cloud storage
  • Authenticate users
  • Complex validation

Without Processing: Form data just disappears into the void

Processing Solutions

Easy Options (No Code):

  • Formspree
  • Google Forms
  • Typeform
  • EmailJS

Advanced Options (Require Backend):

  • Node.js + Express
  • Python + Flask/Django
  • PHP
  • Serverless functions

Section 3: Working with Data Structures

Building Complex Applications with Objects and Arrays

Data-Driven Development

Objects • Arrays • JSON • Template Literals • Console Debugging

Foundation: Modern web applications are built on well-structured data

Complex Data Structures

Real Applications: Combining objects and arrays to model real-world data

Building a Product Catalog

// Real-world data structure
const catalog = {
    storeName: 'Tech Shop',
    currency: 'USD',
    products: [
        {
            id: 1,
            name: 'Laptop',
            price: 999.99,
            inStock: true,
            specs: {
                ram: '16GB',
                storage: '512GB SSD',
                processor: 'Intel i7'
            },
            tags: ['electronics', 'computers', 'featured']
        },
        {
            id: 2,
            name: 'Mouse',
            price: 29.99,
            inStock: true,
            specs: {
                type: 'wireless',
                dpi: 1600
            },
            tags: ['accessories', 'peripherals']
        }
    ]
};

Working with the Data

// Access nested data
console.log(catalog.products[0].name); // 'Laptop'
console.log(catalog.products[0].specs.ram); // '16GB'

// Calculate total inventory value
let totalValue = 0;
for (let i = 0; i < catalog.products.length; i++) {
    totalValue += catalog.products[i].price;
}
console.log(`Total inventory: $${totalValue}`);

// Find products by tag
const featured = [];
for (let i = 0; i < catalog.products.length; i++) {
    if (catalog.products[i].tags.includes('featured')) {
        featured.push(catalog.products[i]);
    }
}
console.log('Featured products:', featured);

// Check stock status
for (let product of catalog.products) {
    const status = product.inStock ? 'Available' : 'Out of Stock';
    console.log(`${product.name}: ${status}`);
}

Template Literals for HTML Generation

Building HTML with JavaScript: Using template literals to create dynamic content

From Data to HTML Strings

// Product data
const product = {
    name: 'Gaming Laptop',
    price: 1299.99,
    rating: 4.5,
    reviews: 128,
    image: 'laptop.jpg',
    features: ['16GB RAM', '1TB SSD', 'RTX 3060']
};

// Generate HTML using template literals
const productHTML = `
    

${product.name}

$${product.price}

${product.rating} stars (${product.reviews} reviews)

    ${product.features.map(f => `
  • ${f}
  • `).join('')}
`; console.log(productHTML); // This string can later be inserted into the page

Building Lists from Arrays

// Array of products
const products = [
    { name: 'Laptop', price: 999, category: 'Electronics' },
    { name: 'Mouse', price: 29, category: 'Accessories' },
    { name: 'Keyboard', price: 79, category: 'Accessories' }
];

// Generate HTML for all products
let catalogHTML = '
'; for (let i = 0; i < products.length; i++) { const product = products[i]; catalogHTML += `

${product.name}

${product.category} $${product.price}
`; } catalogHTML += '
'; console.log(catalogHTML); // This creates a complete HTML structure from data

JSON: JavaScript Object Notation

Data Exchange Format: JSON is how data moves between servers, files, and applications

Working with JSON

// JavaScript object
const userData = {
    id: 123,
    username: 'johndoe',
    email: 'john@example.com',
    profile: {
        firstName: 'John',
        lastName: 'Doe',
        age: 28
    },
    skills: ['JavaScript', 'HTML', 'CSS'],
    isActive: true
};

// Convert to JSON string
const jsonString = JSON.stringify(userData);
console.log(jsonString);
// {"id":123,"username":"johndoe",...}

// Pretty print with indentation
const prettyJSON = JSON.stringify(userData, null, 2);
console.log(prettyJSON);

Parsing JSON Data

// JSON string (from API or file)
const jsonData = `{
    "products": [
        {"id": 1, "name": "Laptop", "price": 999},
        {"id": 2, "name": "Mouse", "price": 29}
    ],
    "total": 1028
}`;

// Parse JSON to JavaScript object
const orderData = JSON.parse(jsonData);
console.log(orderData.products[0].name); // 'Laptop'
console.log(orderData.total); // 1028

// Error handling for invalid JSON
try {
    const data = JSON.parse(jsonData);
    console.log('Valid JSON:', data);
} catch (error) {
    console.error('Invalid JSON:', error.message);
}

Using the Browser Console

Your JavaScript Laboratory: The console is where you test, debug, and explore JavaScript

Console Methods for Data

// Basic output
const products = [
    {name: 'Laptop', price: 999, category: 'Electronics'},
    {name: 'Mouse', price: 29, category: 'Accessories'}
];

console.log('Products:', products);

// Table view for arrays of objects
console.table(products);

// Grouping related output
console.group('Inventory Analysis');
console.log('Total products:', products.length);
console.log('Categories:', ['Electronics', 'Accessories']);
console.groupEnd();

// Timing operations
console.time('Data Processing');
for (let i = 0; i < products.length; i++) {
    // Process each product
}
console.timeEnd('Data Processing');

Debugging with Console

// Tracking variable values
let total = 0;
for (let product of products) {
    console.log(`Processing: ${product.name}`);
    total += product.price;
    console.log(`Running total: $${total}`);
}

// Using console.assert for validation
console.assert(total > 0, 'Total should be positive');
console.assert(products.length > 0, 'Products array is empty');

// Conditional debugging
const DEBUG = true;
if (DEBUG) {
    console.log('Debug mode: Product data', products);
}

// Tracing execution flow
function processOrder(items) {
    console.trace('processOrder called');
    return items.reduce((sum, item) => sum + item.price, 0);
}

const orderTotal = processOrder(products);
console.log('Order total:', orderTotal);

Building a Data-Driven Application

Putting It Together: Using objects, arrays, and templates to build real features

Complete Shopping Cart Example

// Shopping cart data structure
const shoppingCart = {
    items: [],
    
    addItem: function(product, quantity) {
        this.items.push({
            ...product,
            quantity: quantity,
            subtotal: product.price * quantity
        });
        console.log(`Added ${quantity}x ${product.name}`);
    },
    
    getTotal: function() {
        let total = 0;
        for (let item of this.items) {
            total += item.subtotal;
        }
        return total;
    },
    
    generateReceipt: function() {
        let receiptHTML = '
'; receiptHTML += '

Shopping Cart

'; for (let item of this.items) { receiptHTML += `
${item.quantity}x ${item.name} - $${item.subtotal}
`; } receiptHTML += `

Total: $${this.getTotal()}

`; receiptHTML += '
'; return receiptHTML; } };

Using the Shopping Cart

// Sample products
const laptop = {id: 1, name: 'Laptop', price: 999};
const mouse = {id: 2, name: 'Mouse', price: 29};
const keyboard = {id: 3, name: 'Keyboard', price: 79};

// Add items to cart
shoppingCart.addItem(laptop, 1);
shoppingCart.addItem(mouse, 2);
shoppingCart.addItem(keyboard, 1);

// Display cart information
console.log('Cart contents:', shoppingCart.items);
console.log('Total items:', shoppingCart.items.length);
console.log('Cart total: $' + shoppingCart.getTotal());

// Generate HTML receipt
const receipt = shoppingCart.generateReceipt();
console.log(receipt);

// Convert cart to JSON for storage
const cartJSON = JSON.stringify(shoppingCart.items);
console.log('Cart as JSON:', cartJSON);

// Later: restore cart from JSON
const savedCart = JSON.parse(cartJSON);
console.log('Restored cart:', savedCart);

Section 4: Advanced Concepts & Debugging

Professional JavaScript Skills

Level Up Your JavaScript

Type Coercion • Debugging Strategies • Console Mastery • Error Handling

Professional Mindset: Understanding edge cases and debugging efficiently separates good developers from great ones

Type Coercion - JavaScript's Helpful Quirks

The Good and Bad: JavaScript tries to help by converting types, but this can cause unexpected behavior

Common Coercion Surprises

// String concatenation wins over addition
console.log('5' + 3);        // '53' (string)
console.log('5' - 3);        // 2 (number)
console.log('5' * 3);        // 15 (number)

// User input is often strings!
const userAge = '25';  // From any input source
console.log(userAge);        // '25' (string)
console.log(userAge + 5);    // '255' (concatenation!)

// Comparison operators
console.log('10' > 5);       // true (number comparison)
console.log('10' > '5');     // false (string comparison!)

// Boolean coercion in conditionals
if ('0') { /* runs - '0' is truthy! */ }
if (0) { /* doesn't run - 0 is falsy */ }

Safe Coding Practices

// Explicit conversion prevents surprises
const userAge = '25';  // String from any source
const age = Number(userAge);
const nextYear = age + 1; // Correct: 26

// Use strict equality
console.log('5' === 5);      // false (different types)
console.log('5' == 5);       // true (coerced comparison)

// Safe number conversion with validation
function safeNumber(value) {
    const num = Number(value);
    return isNaN(num) ? 0 : num;
}

// Working with user input data
const userData = '  john@example.com  ';
const hasValue = Boolean(userData.trim());
const isEmpty = !userData.trim(); // More idiomatic

// Template literals avoid coercion issues
const message = `You are ${age} years old`; // Clear intent

Mastering the Browser Console

Developer Superpower: The console is your debugging command center - learn to use it effectively

Console Methods Beyond log()

// Different message types
console.log('General information');
console.info('Helpful information');
console.warn('Something might be wrong');
console.error('Definitely a problem');

// Organized output
console.group('Form Validation');
console.log('Checking name field...');
console.log('Checking email field...');
console.groupEnd();

// Table view for objects/arrays
const users = [
    {name: 'John', email: 'john@example.com', age: 25},
    {name: 'Jane', email: 'jane@example.com', age: 30}
];
console.table(users);

// Performance timing
console.time('form-validation');
validateFormData();
console.timeEnd('form-validation');

Advanced Debugging Techniques

// Conditional logging
const DEBUG = true;
function debugLog(message, data) {
    if (DEBUG) {
        console.log(`[DEBUG] ${message}:`, data);
    }
}

// Object inspection
const formData = new FormData(form);
console.log('FormData contents:', Object.fromEntries(formData));

// Stack trace for errors
console.trace('How did we get here?');

// Assert conditions
console.assert(age >= 0, 'Age cannot be negative:', age);

// Clear console programmatically
function resetDebugging() {
    console.clear();
    console.log('Starting fresh debugging session');
}

// Monitor function calls
function validateEmail(email) {
    console.count('validateEmail called');
    return email.includes('@');
}

Debugging Strategies for Real Problems

Systematic Debugging: Reproduce → Isolate → Understand → Fix → Verify

Step-Through Debugging

// Use debugger statement for complex functions
function processOrderData(orderData) {
    debugger; // Execution pauses here in DevTools
    
    const items = orderData.items;
    const customerInfo = orderData.customer;
    
    if (!items || items.length === 0) {
        return { valid: false, error: 'No items in order' };
    }
    
    if (!customerInfo || !customerInfo.email) {
        return { valid: false, error: 'Customer email required' };
    }
    
    return { valid: true, total: calculateTotal(items) };
}

// Strategic console logging for data processing
function debugOrderProcessing(order) {
    console.log('1. Processing order:', order.id);
    console.log('2. Order data:', order);
    
    const validation = processOrderData(order);
    console.log('3. Validation result:', validation);
    
    if (validation.valid) {
        console.log('4. Order total:', validation.total);
    }
}

Common JavaScript Errors

// Null/undefined reference errors
const userData = getUserData(); // Might return null
// userData is null if user doesn't exist
const name = userData.name; // Error if userData is null!

// Safe approach - always check
const userData = getUserData();
if (userData) {
    console.log('User name:', userData.name);
} else {
    console.warn('No user data found');
}

// Array access errors
const products = [];
const firstProduct = products[0]; // undefined
console.log(firstProduct.name); // Error! undefined has no .name

// Safe array access
if (products.length > 0) {
    console.log('First product:', products[0].name);
} else {
    console.log('No products available');
}

// Type conversion errors
const userAge = '25abc'; // Invalid number string
const age = parseInt(userAge, 10); // NaN
if (isNaN(age)) {
    console.error('Invalid age input:', userAge);
    // Handle the error appropriately
} else {
    console.log('Valid age:', age);
}

// Scope errors - undefined functions/variables
function calculateDiscount() {
    // Make sure getDiscountRate is defined
    if (typeof getDiscountRate === 'function') {
        return getDiscountRate();
    } else {
        console.error('getDiscountRate function not found');
        return 0;
    }
}

Error Handling for Better User Experience

Professional Standard: Handle errors gracefully instead of letting the application crash

Try-Catch for Critical Operations

// Safe JSON parsing
function parseJSONSafely(jsonString, defaultValue) {
    try {
        return JSON.parse(jsonString);
    } catch (error) {
        console.warn('Invalid JSON format:', error.message);
        console.log('Returning default value instead');
        return defaultValue;
    }
}

// Safe data processing
function processUserData(userData) {
    try {
        const result = {
            name: userData.name.trim(),
            email: userData.email.toLowerCase(),
            age: Number(userData.age)
        };
        
        if (isNaN(result.age)) {
            throw new Error('Invalid age format');
        }
        
        return { success: true, data: result };
    } catch (error) {
        console.error('Data processing error:', error.message);
        return { success: false, error: error.message };
    }
}

// Safe calculation functions
function calculateTotal(items) {
    try {
        if (!Array.isArray(items)) {
            throw new Error('Items must be an array');
        }
        
        return items.reduce((total, item) => {
            if (typeof item.price !== 'number') {
                throw new Error(`Invalid price for item: ${item.name}`);
            }
            return total + item.price;
        }, 0);
    } catch (error) {
        console.error('Calculation error:', error.message);
        return 0; // Safe fallback
    }
}

Error Logging and Recovery

// Error logging system
const errorLogger = {
    errors: [],
    
    log: function(error, context) {
        const errorRecord = {
            timestamp: new Date().toISOString(),
            message: error.message,
            context: context,
            type: error.name || 'Error'
        };
        
        this.errors.push(errorRecord);
        console.error('Logged error:', errorRecord);
    },
    
    getErrors: function() {
        return this.errors;
    },
    
    clearErrors: function() {
        this.errors = [];
        console.log('Error log cleared');
    }
};

// Application with error recovery
function processOrder(orderData) {
    try {
        // Validate order data
        if (!orderData || typeof orderData !== 'object') {
            throw new Error('Invalid order data');
        }
        
        const items = orderData.items || [];
        const customer = orderData.customer;
        
        if (items.length === 0) {
            throw new Error('Order must contain at least one item');
        }
        
        const total = calculateTotal(items);
        
        return {
            success: true,
            order: {
                id: Date.now(),
                customer: customer,
                items: items,
                total: total
            }
        };
        
    } catch (error) {
        errorLogger.log(error, 'processOrder');
        
        return {
            success: false,
            error: error.message,
            fallback: 'Please check your order data and try again'
        };
    }
}

Section 5: Practical Applications

Bringing It All Together

Transform Static Sites

Static → Interactive • Professional • Engaging • Memorable

Goal: Apply today's concepts to create professional, interactive websites

Connecting Features to Today's Concepts

Everything Connects: Every feature uses multiple concepts we learned today

Building a Navigation Menu

Concepts Applied:

  • Arrays for menu items
  • Objects for page data
  • Template literals for HTML
  • Loops to generate content
  • String concatenation
// Navigation data structure
const navigation = [
    { title: 'Home', url: '/', active: true },
    { title: 'About', url: '/about', active: false },
    { title: 'Projects', url: '/projects', active: false },
    { title: 'Contact', url: '/contact', active: false }
];

// Generate navigation HTML
let navHTML = '';
console.log(navHTML);

Content Management System

Concepts Applied:

  • Nested objects for content
  • Arrays for multiple items
  • Object methods for logic
  • Template literals
  • JSON for data storage
  • Error handling patterns
// Blog post system
const blog = {
    posts: [
        {
            id: 1,
            title: 'Getting Started with JavaScript',
            author: 'Jane Doe',
            date: '2024-09-15',
            content: 'JavaScript is a powerful language...',
            tags: ['javascript', 'tutorial', 'beginners']
        }
    ],
    
    generatePostHTML: function(postId) {
        const post = this.posts.find(p => p.id === postId);
        if (!post) return '

Post not found

'; return `

${post.title}

By ${post.author} on ${post.date}

${post.content}

Tags: ${post.tags.join(', ')}

`; } };

Data Validation with JavaScript

Pure JavaScript Validation: Using objects and functions to validate data

Form Data Structure

// Contact form data object
const contactData = {
    name: 'John Doe',
    email: 'john@example.com',
    message: 'Hello, I would like to discuss a project.',
    phone: '555-123-4567',
    company: 'Tech Corp'
};

// Validation rules object
const validationRules = {
    name: {
        required: true,
        minLength: 2,
        maxLength: 50
    },
    email: {
        required: true,
        pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    },
    message: {
        required: true,
        minLength: 10,
        maxLength: 500
    },
    phone: {
        required: false,
        pattern: /^\d{3}-\d{3}-\d{4}$/
    }
};

Validation Functions

// Validation system using objects and functions
const validator = {
    errors: [],
    
    validateField: function(fieldName, value, rules) {
        this.errors = [];
        
        // Required field check
        if (rules.required && (!value || value.trim() === '')) {
            this.errors.push(`${fieldName} is required`);
            return false;
        }
        
        // Skip other checks if field is empty and not required
        if (!value || value.trim() === '') {
            return true;
        }
        
        // Length validation
        if (rules.minLength && value.length < rules.minLength) {
            this.errors.push(`${fieldName} must be at least ${rules.minLength} characters`);
        }
        
        if (rules.maxLength && value.length > rules.maxLength) {
            this.errors.push(`${fieldName} cannot exceed ${rules.maxLength} characters`);
        }
        
        // Pattern validation (email, phone)
        if (rules.pattern && !rules.pattern.test(value)) {
            this.errors.push(`${fieldName} format is invalid`);
        }
        
        return this.errors.length === 0;
    },
    
    validateForm: function(data, rules) {
        let allValid = true;
        const results = {};
        
        for (let field in rules) {
            const isValid = this.validateField(field, data[field], rules[field]);
            results[field] = {
                valid: isValid,
                errors: [...this.errors]
            };
            if (!isValid) allValid = false;
        }
        
        return { valid: allValid, fields: results };
    }
};

Using the Validation System

Practical Application: Testing and using our validation functions

Testing Valid Data

// Test with valid data
const validContact = {
    name: 'Jane Smith',
    email: 'jane@example.com',
    message: 'I would love to work together on a project.',
    phone: '555-123-4567'
};

// Validate the entire form
const result = validator.validateForm(validContact, validationRules);

console.log('Validation result:', result.valid); // true
console.log('Field details:', result.fields);

// Generate success message
if (result.valid) {
    console.log(`✅ Form is valid! Ready to send message from ${validContact.name}`);
}

Testing Invalid Data

// Test with invalid data
const invalidContact = {
    name: 'J',  // Too short
    email: 'not-an-email',  // Invalid format
    message: '',  // Required but empty
    phone: '555-1234'  // Wrong format
};

// Validate and collect errors
const result = validator.validateForm(invalidContact, validationRules);

console.log('Validation result:', result.valid); // false

// Display all errors
for (let field in result.fields) {
    if (!result.fields[field].valid) {
        console.log(`❌ ${field} errors:`);
        result.fields[field].errors.forEach(error => {
            console.log(`   - ${error}`);
        });
    }
}

// Could generate HTML error messages here
console.log('Form submission blocked due to validation errors');

Before and After Comparison

Transformation: See the professional difference JavaScript makes

❌ Hard-Coded Websites (Before)

  • All content written directly in HTML
  • No data validation
  • Difficult to maintain and update
  • Limited scalability
  • No error handling
  • Repetitive, copy-paste development
  • Looks amateurish

Employer Impression:

"Basic HTML skills, doesn't understand modern development practices"

✅ Data-Driven Websites (After)

  • Content generated from structured data
  • Robust validation systems
  • Easy to maintain and scale
  • Professional error handling
  • Reusable components and functions
  • Clean, organized code structure
  • Looks professionally developed

Employer Impression:

"Strong JavaScript fundamentals, understands data structures, ready for frameworks"

Ready to Build with Data!

What You've Learned

  • JavaScript Fundamentals: Variables, objects, arrays in practice
  • HTML Forms: Structure, input types, semantic markup
  • Data Structures: Complex objects, nested arrays, JSON
  • Professional Skills: Debugging, validation, error handling
  • Integration: How concepts work together

What You Can Build

  • Data Validation: Robust form checking systems
  • Content Generation: HTML from data structures
  • Application Logic: Shopping carts, user profiles
  • JSON Integration: Data import/export systems
  • Template Systems: Reusable content patterns

Let's Code! Time for Data-Driven Development

You have the foundation - now let's build something powerful