Week 09: JavaScript Objects, JSON & AJAX

Unit III - Data Handling & API Communication

Working with data in modern JavaScript!

What You'll Learn

  • JavaScript Objects & Prototypes
  • JSON format and methods
  • Fetch API for HTTP requests
  • Promises and async/await
  • Error handling in async code

Why This Matters

Modern web apps constantly communicate with servers to fetch and send data. Understanding JSON and async JavaScript is essential for building dynamic applications!

Press → or click Next to continue

JavaScript Objects

Objects are collections of key-value pairs - the foundation of data in JavaScript.

Creating Objects

// Object literal (most common)
const person = {
    name: 'Alice',
    age: 25,
    email: 'alice@example.com'
};

// Constructor function
function Person(name, age) {
    this.name = name;
    this.age = age;
}
const bob = new Person('Bob', 30);

// Object.create()
const student = Object.create(person);
student.grade = 'A';

Accessing Properties

// Dot notation
console.log(person.name);     // 'Alice'

// Bracket notation
console.log(person['age']);   // 25

// Dynamic property access
const key = 'email';
console.log(person[key]);     // 'alice@...'

// Check if property exists
'name' in person              // true
person.hasOwnProperty('name') // true

// Delete property
delete person.email;

Object Shorthand (ES6+)

const name = 'Alice';
const age = 25;
const person = { name, age };  // Same as { name: name, age: age }

Object Methods

Objects can contain functions - called methods.

Defining Methods

const calculator = {
    value: 0,

    // Method shorthand (ES6)
    add(n) {
        this.value += n;
        return this;  // for chaining
    },

    subtract(n) {
        this.value -= n;
        return this;
    },

    // Traditional syntax
    multiply: function(n) {
        this.value *= n;
        return this;
    },

    getValue() {
        return this.value;
    }
};

// Method chaining
calculator.add(10).subtract(3).multiply(2);
console.log(calculator.getValue()); // 14

The 'this' Keyword

const user = {
    name: 'Alice',
    greet() {
        console.log(`Hi, I'm ${this.name}`);
    }
};

user.greet();  // "Hi, I'm Alice"

// 'this' depends on how function is called
const greet = user.greet;
greet();  // "Hi, I'm undefined"

// Fix with bind
const boundGreet = user.greet.bind(user);
boundGreet();  // "Hi, I'm Alice"

// Arrow functions don't have own 'this'
const obj = {
    name: 'Test',
    arrow: () => console.log(this.name),
    regular() { console.log(this.name); }
};

Prototypes & Inheritance

JavaScript uses prototypal inheritance - objects inherit from other objects.

Prototype Chain

const animal = {
    eat() {
        console.log('Eating...');
    }
};

const dog = Object.create(animal);
dog.bark = function() {
    console.log('Woof!');
};

dog.bark();  // 'Woof!'
dog.eat();   // 'Eating...' (inherited)

// Check prototype
Object.getPrototypeOf(dog) === animal  // true
animal.isPrototypeOf(dog)              // true

ES6 Classes (Syntactic Sugar)

class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name);  // Call parent constructor
        this.breed = breed;
    }

    speak() {
        console.log(`${this.name} barks!`);
    }
}

const rex = new Dog('Rex', 'German Shepherd');
rex.speak();  // "Rex barks!"

Note: ES6 classes are just syntactic sugar over JavaScript's prototype-based inheritance.

What is JSON?

JavaScript Object Notation - A lightweight data interchange format.

JSON Syntax Rules

  • Data in key-value pairs
  • Keys MUST be double-quoted strings
  • Values can be: strings, numbers, booleans, null, arrays, objects
  • No trailing commas
  • No comments allowed
  • No functions or undefined
// Valid JSON
{
    "name": "Alice",
    "age": 25,
    "isStudent": true,
    "courses": ["Math", "Physics"],
    "address": {
        "city": "Chennai",
        "zip": "600001"
    },
    "spouse": null
}

JSON vs JavaScript Object

// JavaScript Object
const jsObj = {
    name: 'Alice',       // unquoted key OK
    'full-name': 'Alice',
    greet() {},          // functions OK
    value: undefined     // undefined OK
};

// JSON (string format)
const json = `{
    "name": "Alice",
    "full-name": "Alice Smith"
}`;

// JSON must be a string!
// JavaScript objects are in memory

Common Mistakes:

  • Using single quotes for keys
  • Trailing commas
  • Including functions

JSON Methods

Convert between JSON strings and JavaScript objects.

JSON.parse()

Convert JSON string to JavaScript object

const jsonString = `{
    "name": "Alice",
    "age": 25,
    "hobbies": ["reading", "coding"]
}`;

const user = JSON.parse(jsonString);

console.log(user.name);      // "Alice"
console.log(user.hobbies[0]); // "reading"

// With reviver function
const data = '{"date": "2024-01-15"}';
const obj = JSON.parse(data, (key, value) => {
    if (key === 'date') {
        return new Date(value);
    }
    return value;
});

JSON.stringify()

Convert JavaScript object to JSON string

const user = {
    name: 'Alice',
    age: 25,
    password: 'secret'  // sensitive!
};

// Basic stringify
const json = JSON.stringify(user);
// '{"name":"Alice","age":25,"password":"secret"}'

// Pretty print with indentation
const pretty = JSON.stringify(user, null, 2);

// Filter properties (replacer)
const safe = JSON.stringify(user, ['name', 'age']);
// '{"name":"Alice","age":25}'

// Custom replacer function
const filtered = JSON.stringify(user, (key, value) => {
    if (key === 'password') return undefined;
    return value;
});

Error Handling

try {
    const data = JSON.parse('invalid json');
} catch (error) {
    console.error('Parse error:', error.message);
}

Introduction to AJAX

Asynchronous JavaScript And XML - Communicate with servers without reloading the page.

What is AJAX?

  • Send/receive data in the background
  • Update parts of page without refresh
  • Originally used XMLHttpRequest
  • Modern approach: Fetch API

Common Use Cases

  • Load content on scroll (infinite scroll)
  • Form submission without page reload
  • Auto-save drafts
  • Search suggestions
  • Chat applications

XMLHttpRequest (Old Way)

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data');

xhr.onload = function() {
    if (xhr.status === 200) {
        const data = JSON.parse(xhr.responseText);
        console.log(data);
    }
};

xhr.onerror = function() {
    console.error('Request failed');
};

xhr.send();

Note: XMLHttpRequest is verbose and callback-based. Modern code uses the Fetch API instead!

Fetch API Basics

The modern way to make HTTP requests in JavaScript.

GET Request

// Basic fetch (returns Promise)
fetch('https://api.example.com/users')
    .then(response => {
        if (!response.ok) {
            throw new Error('Network error');
        }
        return response.json();
    })
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.error('Error:', error);
    });

// Response methods
response.json()   // Parse as JSON
response.text()   // Get as text
response.blob()   // Get as binary
response.headers  // Access headers
response.status   // HTTP status code
response.ok       // true if 200-299

POST Request

fetch('https://api.example.com/users', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        name: 'Alice',
        email: 'alice@example.com'
    })
})
.then(response => response.json())
.then(data => {
    console.log('Created:', data);
})
.catch(error => {
    console.error('Error:', error);
});

// Other methods: PUT, PATCH, DELETE
fetch(url, { method: 'DELETE' })
fetch(url, {
    method: 'PUT',
    body: JSON.stringify(updatedData)
})

Promises

A Promise represents a value that may be available now, later, or never.

Promise States

  • Pending: Initial state, waiting
  • Fulfilled: Operation completed successfully
  • Rejected: Operation failed
// Creating a Promise
const myPromise = new Promise((resolve, reject) => {
    // Async operation
    setTimeout(() => {
        const success = true;
        if (success) {
            resolve('Data loaded!');
        } else {
            reject(new Error('Failed to load'));
        }
    }, 1000);
});

// Using the Promise
myPromise
    .then(result => console.log(result))
    .catch(error => console.error(error));

Promise Chaining

fetch('/api/user/1')
    .then(response => response.json())
    .then(user => {
        console.log(user.name);
        return fetch(`/api/posts?userId=${user.id}`);
    })
    .then(response => response.json())
    .then(posts => {
        console.log('Posts:', posts);
    })
    .catch(error => {
        // Catches ANY error in the chain
        console.error('Error:', error);
    })
    .finally(() => {
        // Always runs
        console.log('Request completed');
    });

Each .then() returns a new Promise, enabling chaining!

Async/Await

Syntactic sugar that makes Promises look like synchronous code.

Basic Syntax

// async function always returns a Promise
async function fetchUser(id) {
    // await pauses until Promise resolves
    const response = await fetch(`/api/users/${id}`);
    const user = await response.json();
    return user;
}

// Using async function
fetchUser(1)
    .then(user => console.log(user));

// Or with IIFE
(async () => {
    const user = await fetchUser(1);
    console.log(user);
})();

Error Handling

async function fetchData() {
    try {
        const response = await fetch('/api/data');

        if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
        }

        const data = await response.json();
        return data;

    } catch (error) {
        console.error('Fetch failed:', error);
        throw error;  // Re-throw if needed
    } finally {
        console.log('Cleanup...');
    }
}

// Sequential vs Parallel
async function loadAll() {
    // Sequential (slow)
    const a = await fetchA();
    const b = await fetchB();

    // Parallel (fast!)
    const [a, b] = await Promise.all([
        fetchA(), fetchB()
    ]);
}

Promise Utilities

Static methods on Promise for handling multiple promises.

Promise.all()

// Wait for ALL promises to resolve
// Fails fast - rejects if ANY fails

const urls = [
    '/api/users',
    '/api/posts',
    '/api/comments'
];

const promises = urls.map(url => fetch(url));

Promise.all(promises)
    .then(responses => {
        return Promise.all(
            responses.map(r => r.json())
        );
    })
    .then(([users, posts, comments]) => {
        console.log(users, posts, comments);
    })
    .catch(error => {
        console.error('One request failed:', error);
    });

Other Utilities

// Promise.allSettled() - Wait for all, never rejects
const results = await Promise.allSettled([
    fetch('/api/a'),
    fetch('/api/b')
]);
// [{status:'fulfilled', value:...}, {status:'rejected', reason:...}]

// Promise.race() - First to resolve/reject wins
const fastest = await Promise.race([
    fetch('/api/server1'),
    fetch('/api/server2')
]);

// Promise.any() - First to resolve wins (ignores rejections)
const first = await Promise.any([
    fetch('/api/a'),
    fetch('/api/b')
]);

// Create resolved/rejected promises
Promise.resolve('value');
Promise.reject(new Error('failed'));

CampusKart Milestone: Cart & API

Deliverable: Working cart with localStorage + products loaded from JSON

What to Build

  • Product class with id, title, price, category, seller
  • Product catalog loaded from JSON file using fetch()
  • Cart stored in localStorage (persists on refresh!)
  • Wishlist using localStorage
  • Cart total and item count display
  • "Clear Cart" and individual remove

Unit III Complete!

Your CampusKart has: structure (HTML), style (CSS), interactivity (DOM/Events), and memory (localStorage/JSON).

Next unit: We give it a real backend with Node.js!

Push to GitHub — "Unit III Complete" milestone.

Video Resources

Frontend Masters

JS: The Hard Parts v2

JavaScript.info

Fetch API Tutorial

JSONPlaceholder

Free Fake API

Practice Exercises

Exercise 1: User Cards

  • Fetch users from API
  • Display as cards
  • Show loading state

Exercise 2: Search App

  • Search input with debounce
  • Fetch results from API
  • Display filtered results

Exercise 3: Weather App

  • Get user location
  • Fetch weather data
  • Display conditions

Exercise 4: CRUD App

  • Create, Read, Update, Delete
  • Use all HTTP methods
  • Handle errors gracefully

Week 09 Summary

Key Concepts

  • Objects store key-value pairs
  • Prototypes enable inheritance
  • JSON is text-based data format
  • JSON.parse() / JSON.stringify()
  • Fetch API for HTTP requests
  • Promises for async operations
  • async/await for cleaner code

Best Practices

  • Always handle errors in async code
  • Use async/await over raw Promises
  • Check response.ok before parsing
  • Use Promise.all for parallel requests
  • Show loading states to users

Next Week

Week 10: Node.js Foundations!