${product.name}
$${product.price}
-
${product.features.map(f => `
- ${f} `).join('')}
UC Berkeley School of Information
September 15, 2024
Building Confidence with Core Concepts
Variables • Arrays • Objects • Data Types
Quick Check: Who can tell me the three ways to declare variables in JavaScript?
// 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
Real World: Lists of data (skills, menu items, products) are stored as arrays
// 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']
// 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
Common Misconception: "const means the object can't change"
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!
// 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');
}
};
// 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!
// 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
Interactive Review: Let's test your understanding before moving forward
From Static to Interactive
Form Structure • Input Types • Validation • Processing
Real-World Application: Every professional website needs user input - contact forms, login, search, etc.
Think Beyond Contact Forms: Login, search, e-commerce, surveys, file uploads, settings...
HTML Forms Provide:
HTML Cannot:
Best Practice: Start with semantic HTML, enhance with JavaScript
<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>
Accessibility: Proper labels are essential for screen readers
Mobile-First Benefit: Each input type triggers the appropriate mobile keyboard
<!-- 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>
<!-- 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">
Critical Understanding: HTML forms can't send emails or save data by themselves
Without Processing: Form data just disappears into the void
Easy Options (No Code):
Advanced Options (Require Backend):
Data-Driven Development
Objects • Arrays • JSON • Template Literals • Console Debugging
Foundation: Modern web applications are built on well-structured data
Real Applications: Combining objects and arrays to model real-world data
// 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']
}
]
};
// 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}`);
}
Building HTML with JavaScript: Using template literals to create dynamic content
// 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
// 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
Data Exchange Format: JSON is how data moves between servers, files, and applications
// 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);
// 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);
}
Your JavaScript Laboratory: The console is where you test, debug, and explore JavaScript
// 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');
// 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);
Putting It Together: Using objects, arrays, and templates to build real features
// 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;
}
};
// 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);
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
The Good and Bad: JavaScript tries to help by converting types, but this can cause unexpected behavior
// 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 */ }
// 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
Developer Superpower: The console is your debugging command center - learn to use it effectively
// 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');
// 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('@');
}
Systematic Debugging: Reproduce → Isolate → Understand → Fix → Verify
// 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);
}
}
// 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;
}
}
Professional Standard: Handle errors gracefully instead of letting the application crash
// 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 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'
};
}
}
Transform Static Sites
Static → Interactive • Professional • Engaging • Memorable
Goal: Apply today's concepts to create professional, interactive websites
Everything Connects: Every feature uses multiple concepts we learned today
Concepts Applied:
// 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);
Concepts Applied:
// 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(', ')}
`;
}
};
Pure JavaScript Validation: Using objects and functions to validate data
// 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 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 };
}
};
Practical Application: Testing and using our validation functions
// 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}`);
}
// 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');
Transformation: See the professional difference JavaScript makes
Employer Impression:
"Basic HTML skills, doesn't understand modern development practices"
Employer Impression:
"Strong JavaScript fundamentals, understands data structures, ready for frameworks"
You have the foundation - now let's build something powerful