Internet Programming Laboratory
Unit 4: JavaScript Core & ES6+ Development
Variables, Data Types, Operators, Control Flow, Arrow Functions, Template Literals, Destructuring, Spread/Rest, Modules, Promises, Fetch API, async/await, JSON, Local Storage — the engine that makes the web interactive.
🏢 Industry-Aligned | 📝 15 MCQs (Bloom's Taxonomy) | 🔬 5 Lab Exercises | 💼 Interview Prep
Why This Chapter Matters in 2025
HTML gives you the skeleton. CSS gives you the skin. JavaScript gives you the brain. Without JavaScript, every website is a static poster — no interactivity, no form validation, no dynamic content, no API calls, no user experience. JavaScript is the only programming language that runs natively in every browser on Earth.
In 2025, JavaScript isn't optional — it's the most used programming language in the world for the 12th year running (Stack Overflow Developer Survey). Every Indian tech company — TCS, Infosys, Wipro, Flipkart, Swiggy, CRED — requires JavaScript proficiency. React, Angular, Vue, Node.js, Next.js — all built on JavaScript.
🏢 Industry Connection — JavaScript Powers Everything
PhonePe — India's #1 payments app. Their entire web checkout flow — UPI ID validation, real-time payment status polling, QR code generation — runs on JavaScript. The fetch() API calls their backend 50 million times per day.
Swiggy — When you search for "biryani" and results appear instantly without page reload? JavaScript fetch() + async/await. When your cart total updates as you add items? JavaScript DOM manipulation. When your delivery ETA counts down? setInterval().
Razorpay — Their payment gateway SDK is 100% JavaScript. When a merchant integrates Razorpay, they write <script src="razorpay.js"> and call new Razorpay(options). ES6 modules, Promises, and async/await are the backbone.
Prerequisite Checklist ✅
- ✅ Completed Units 1–3 (HTML5 + CSS3 — you need a page to add JS to)
- ✅ VS Code with the Live Server extension
- ✅ Chrome DevTools — you'll live in the Console tab this entire unit (press F12 → Console)
- ✅ Basic understanding of programming concepts (variables, conditions, loops) from any language
Learning Outcomes — Bloom's Taxonomy
| Bloom's Level | Learning Outcome |
|---|---|
| L1 — Remember | Recall the syntax for let/const/var, data types, operators, control flow structures, and ES6 features (arrow functions, template literals, destructuring) |
| L2 — Understand | Explain the difference between == and ===, block vs function scope, synchronous vs asynchronous execution, and how Promises work |
| L3 — Apply | Write JavaScript programs using ES6+ syntax: arrow functions, destructuring, spread/rest, template literals, fetch() with async/await, and localStorage |
| L4 — Analyze | Debug JavaScript code using Chrome DevTools — identify scope issues, type coercion bugs, and async timing errors |
| L5 — Evaluate | Compare callbacks vs Promises vs async/await for handling asynchronous operations and justify which pattern to use |
| L6 — Create | Build a complete interactive web application using JavaScript ES6+ with API integration, form validation, and persistent storage |
Concept Explanations — Theory, Earned
3.1 Embedding JavaScript in HTML
Three ways to add JavaScript
| Method | Syntax | Use Case | Industry? |
|---|---|---|---|
| External (file) | <script src="app.js"></script> | All production code | ✅ Always |
| Internal (inline) | <script> ... </script> | Quick demos, prototyping | ⚠️ Rare |
| Inline attribute | onclick="doSomething()" | Never in modern code | ❌ Avoid |
HTML
<!-- 📁 index.html -->
<!-- METHOD 1: External JS (INDUSTRY STANDARD) -->
<!-- Place at END of <body> or use defer -->
<head>
<script src="js/app.js" defer></script> <!-- defer = load after HTML parsed -->
</head>
<!-- METHOD 2: At end of body (traditional) -->
<body>
<!-- ... your HTML content ... -->
<script src="js/app.js"></script> <!-- Loads after all HTML is rendered -->
</body>
<button onclick="handleClick()">) — replaced by addEventListener() in modern JavaScript. Inline handlers mix HTML and JS, making code unmaintainable. Every company code review will reject inline handlers.3.2 Variables — var, let, and const
The Three Keywords
| Keyword | Scope | Reassign? | Redeclare? | Hoisted? | Use in 2025? |
|---|---|---|---|---|---|
var | Function scope | ✅ Yes | ✅ Yes | ✅ (as undefined) | ❌ Never |
let | Block scope {} | ✅ Yes | ❌ No | ❌ (TDZ error) | ✅ When value changes |
const | Block scope {} | ❌ No | ❌ No | ❌ (TDZ error) | ✅ Default choice |
JavaScript
// 🏢 INDUSTRY RULE: Use const by default. Use let only when reassignment is needed.
// Never use var — it's legacy ES5.
// ✅ const — value never changes
const API_URL = 'https://api.swiggy.com/restaurants';
const MAX_ITEMS = 50;
const user = { name: 'Rahul', city: 'Bengaluru' };
// ✅ let — value will be reassigned
let cartTotal = 0;
let isLoggedIn = false;
// ❌ var — DON'T USE — function scoped, leaks out of blocks
var oldWay = 'avoid this'; // Legacy code only
Block Scope vs Function Scope — The Critical Difference
JavaScript
// 🚨 THE var BUG — one of the most common interview questions
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3 😱 (var is function-scoped, shares same i)
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 0, 1, 2 ✅ (let is block-scoped, each iteration gets its own i)
const doesn't mean "immutable". const prevents reassignment, not mutation. A const object's properties CAN be changed. const user = {}; user.name = 'Priya'; is valid. user = {} is NOT.
3.3 Data Types & Type Coercion
JavaScript's 8 Data Types
| Type | Example | typeof | Category |
|---|---|---|---|
| String | 'Hello', "World", `Template` | "string" | Primitive |
| Number | 42, 3.14, NaN, Infinity | "number" | Primitive |
| BigInt | 9007199254740991n | "bigint" | Primitive |
| Boolean | true, false | "boolean" | Primitive |
| Undefined | undefined | "undefined" | Primitive |
| Null | null | "object" ⚠️ | Primitive |
| Symbol | Symbol('id') | "symbol" | Primitive |
| Object | {}, [], function(){} | "object" | Reference |
Type Coercion — JavaScript's Biggest Trap
JavaScript
// 🚨 == (loose equality) performs TYPE COERCION
console.log(5 == '5'); // true 😱 (string '5' coerced to number 5)
console.log(0 == false); // true 😱 (false coerced to 0)
console.log('' == false); // true 😱 ('' coerced to 0, false to 0)
console.log(null == undefined); // true 😱
// ✅ === (strict equality) — NO coercion — ALWAYS USE THIS
console.log(5 === '5'); // false ✅ (different types)
console.log(0 === false); // false ✅
console.log('' === false); // false ✅
// String + Number coercion
console.log('5' + 3); // '53' (string concatenation — + prefers strings)
console.log('5' - 3); // 2 (subtraction forces number conversion)
console.log('5' * 3); // 15 (multiplication forces number)
=== and !==. At Flipkart, Swiggy, and every serious company, ESLint rules enforce ===. Using == in a PR will trigger an automatic lint failure.3.4 Operators — Complete Reference
JavaScript
// ═══ ARITHMETIC ═══
10 + 3 // 13 (addition)
10 - 3 // 7 (subtraction)
10 * 3 // 30 (multiplication)
10 / 3 // 3.333... (division — always float!)
10 % 3 // 1 (modulus — remainder)
2 ** 10 // 1024 (exponentiation — ES7)
// ═══ COMPARISON ═══
5 === 5 // true (strict equality — ALWAYS USE)
5 !== '5' // true (strict inequality)
5 > 3 // true
5 >= 5 // true
// ═══ LOGICAL ═══
true && false // false (AND — both must be true)
true || false // true (OR — at least one true)
!true // false (NOT — inverts)
// ═══ TERNARY (inline if-else) ═══
const status = age >= 18 ? 'Adult' : 'Minor';
// ═══ NULLISH COALESCING ?? (ES2020) ═══
// Returns right side ONLY if left is null or undefined
const username = user.name ?? 'Guest';
// Unlike ||, ?? does NOT treat 0, '', false as "empty"
const count = 0;
console.log(count || 10); // 10 😱 (|| treats 0 as falsy)
console.log(count ?? 10); // 0 ✅ (?? only checks null/undefined)
// ═══ OPTIONAL CHAINING ?. (ES2020) ═══
const city = user?.address?.city; // undefined if any level is null/undefined
// Without ?.: user.address.city → TypeError if address is undefined!
3.5 Control Flow & Loops
JavaScript
// ═══ IF-ELSE ═══
const score = 78;
if (score >= 90) {
console.log('A+ Grade');
} else if (score >= 75) {
console.log('A Grade'); // ← This runs
} else {
console.log('Below A');
}
// ═══ SWITCH ═══
const paymentMethod = 'UPI';
switch (paymentMethod) {
case 'UPI': console.log('Processing via PhonePe/GPay'); break;
case 'Card': console.log('Processing via Razorpay'); break;
case 'COD': console.log('Cash on Delivery'); break;
default: console.log('Unknown payment method');
}
// ═══ LOOPS ═══
// for loop (classic)
for (let i = 0; i < 5; i++) {
console.log(`Item ${i}`);
}
// for...of (iterate VALUES — arrays, strings, Maps, Sets)
const cities = ['Delhi', 'Mumbai', 'Bengaluru', 'Chennai'];
for (const city of cities) {
console.log(city); // Delhi, Mumbai, Bengaluru, Chennai
}
// for...in (iterate KEYS — objects)
const student = { name: 'Priya', age: 20, branch: 'CSE' };
for (const key in student) {
console.log(`${key}: ${student[key]}`);
}
// while loop
let retries = 3;
while (retries > 0) {
console.log(`Retrying... ${retries} attempts left`);
retries--;
}
// do...while (runs at least once)
let input;
do {
input = prompt('Enter a number greater than 10:');
} while (Number(input) <= 10);
3.6 Functions — Declarations, Expressions, and Arrow Functions
JavaScript
// ═══ FUNCTION DECLARATION (hoisted) ═══
function calculateGST(price, rate = 0.18) {
return price * rate;
}
// ═══ FUNCTION EXPRESSION (not hoisted) ═══
const calculateDiscount = function(price, percent) {
return price * (percent / 100);
};
// ═══ ARROW FUNCTION (ES6 — INDUSTRY STANDARD) ═══
const add = (a, b) => a + b; // Implicit return
const greet = name => `Hello, ${name}!`; // Single param, no parens needed
const getUser = () => ({ name: 'Rahul' }); // Return object (wrap in parens)
// ═══ Multi-line arrow function ═══
const processOrder = (items, coupon) => {
let total = items.reduce((sum, item) => sum + item.price, 0);
if (coupon) total *= 0.9; // 10% discount
const gst = total * 0.18;
return { subtotal: total, gst, grandTotal: total + gst };
};
// ═══ Default Parameters ═══
const createUser = (name, role = 'student', active = true) => {
return { name, role, active };
};
createUser('Priya'); // { name: 'Priya', role: 'student', active: true }
createUser('Amit', 'admin'); // { name: 'Amit', role: 'admin', active: true }
3.7 ES6+ Features — Modern JavaScript
Template Literals
JavaScript
// ❌ OLD: String concatenation
const msg = 'Hello, ' + name + '! You have ' + count + ' items.';
// ✅ NEW: Template literals (backticks)
const msg = `Hello, ${name}! You have ${count} items.`;
// Multi-line strings
const html = `
<div class="card">
<h2>${product.name}</h2>
<p>₹${product.price.toLocaleString('en-IN')}</p>
</div>
`;
// Tagged template (used in styled-components, GraphQL)
const query = gql`query { users { name email } }`;
Destructuring — Arrays & Objects
JavaScript
// ═══ OBJECT DESTRUCTURING ═══
const order = {
id: 'ORD-001',
customer: 'Priya',
total: 450,
address: { city: 'Mumbai', pin: '400001' }
};
// Extract properties into variables
const { id, customer, total } = order;
console.log(customer); // 'Priya'
// Rename while destructuring
const { customer: buyerName } = order;
console.log(buyerName); // 'Priya'
// Nested destructuring
const { address: { city, pin } } = order;
console.log(city); // 'Mumbai'
// Default values
const { discount = 0 } = order;
console.log(discount); // 0 (property doesn't exist, uses default)
// ═══ ARRAY DESTRUCTURING ═══
const scores = [95, 87, 92, 78];
const [first, second, ...rest] = scores;
console.log(first); // 95
console.log(rest); // [92, 78]
// Swap variables without temp
let a = 1, b = 2;
[a, b] = [b, a]; // a=2, b=1 ✅
Spread & Rest Operators
JavaScript
// ═══ SPREAD (...) — Expands arrays/objects ═══
// Array spread
const fruits = ['🍎', '🍌'];
const moreFruits = [...fruits, '🥭', '🍇'];
// ['🍎', '🍌', '🥭', '🍇']
// Object spread (shallow copy + override)
const defaults = { theme: 'dark', lang: 'en', fontSize: 16 };
const userPrefs = { ...defaults, lang: 'hi', fontSize: 18 };
// { theme: 'dark', lang: 'hi', fontSize: 18 }
// ═══ REST (...) — Collects remaining items ═══
const logFirst = (first, ...others) => {
console.log(`First: ${first}`);
console.log(`Rest: ${others}`);
};
logFirst('Delhi', 'Mumbai', 'Chennai');
// First: Delhi
// Rest: Mumbai,Chennai
ES6 Modules — import/export
JavaScript
// 📁 utils.js — Named exports
export const formatPrice = (price) => `₹${price.toLocaleString('en-IN')}`;
export const calcGST = (price) => price * 0.18;
// 📁 api.js — Default export
const fetchRestaurants = async () => { /* ... */ };
export default fetchRestaurants;
// 📁 app.js — Importing
import fetchRestaurants from './api.js'; // Default import
import { formatPrice, calcGST } from './utils.js'; // Named imports
import * as utils from './utils.js'; // Namespace import
HTML
<!-- Enable modules in HTML -->
<script type="module" src="js/app.js"></script>
Error Handling — try/catch/finally
JavaScript
// 🏢 INDUSTRY PATTERN: Always wrap API calls in try/catch
const loadUserProfile = async (userId) => {
try {
const res = await fetch(`/api/users/${userId}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const user = await res.json();
return user;
} catch (error) {
console.error('Failed to load profile:', error.message);
return null; // Graceful fallback
} finally {
hideLoadingSpinner(); // Runs whether success or failure
}
};
3.8 JavaScript Objects & JSON
JavaScript
// ═══ OBJECTS ═══
const restaurant = {
name: 'Paradise Biryani',
city: 'Hyderabad',
rating: 4.5,
isVeg: false,
menu: ['Chicken Biryani', 'Mutton Biryani', 'Paneer Biryani'],
// Method (shorthand ES6)
getInfo() {
return `${this.name} — ${this.city} (${this.rating}⭐)`;
}
};
// Accessing properties
console.log(restaurant.name); // Dot notation
console.log(restaurant['city']); // Bracket notation (dynamic keys)
console.log(restaurant.getInfo()); // Paradise Biryani — Hyderabad (4.5⭐)
// Shorthand property names (ES6)
const name = 'Priya', age = 21;
const student = { name, age }; // Same as { name: name, age: age }
// Object methods
Object.keys(restaurant); // ['name', 'city', 'rating', 'isVeg', 'menu', 'getInfo']
Object.values(restaurant); // ['Paradise Biryani', 'Hyderabad', 4.5, false, [...], ƒ]
Object.entries(restaurant); // [['name','Paradise Biryani'], ['city','Hyderabad'], ...]
JSON — JavaScript Object Notation
JavaScript
// 🏢 JSON is THE data format for API communication
// Every API at Swiggy, Flipkart, Razorpay sends/receives JSON
// JavaScript Object → JSON string
const order = { id: 42, item: 'Biryani', price: 350 };
const jsonString = JSON.stringify(order);
console.log(jsonString);
// '{"id":42,"item":"Biryani","price":350}'
// JSON string → JavaScript Object
const parsed = JSON.parse(jsonString);
console.log(parsed.item); // 'Biryani'
// Pretty print (useful for debugging)
console.log(JSON.stringify(order, null, 2));
// {
// "id": 42,
// "item": "Biryani",
// "price": 350
// }
application/json.3.9 Fetch API, Promises & async/await
Synchronous vs Asynchronous
ASCII
SYNCHRONOUS (blocking) ASYNCHRONOUS (non-blocking)
┌─────────────────┐ ┌─────────────────┐
│ Task 1 (1 sec) │ │ Task 1 (1 sec) │──┐
├─────────────────┤ ├─────────────────┤ │ Runs in
│ Task 2 (2 sec) │ ← waits │ Task 2 starts │ │ background
├─────────────────┤ │ Task 3 starts │ │
│ Task 3 (1 sec) │ ← waits │ Task 2 done ✓ │←─┘
├─────────────────┤ │ Task 1 done ✓ │
│ Total: 4 sec │ │ Total: ~2 sec │
└─────────────────┘ └─────────────────┘
Promises — The Foundation
JavaScript
// A Promise represents a value that will be available in the future
// States: pending → fulfilled (resolved) or rejected
const fetchMenu = (restaurantId) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (restaurantId === 1) {
resolve(['Biryani', 'Naan', 'Raita']);
} else {
reject(new Error('Restaurant not found'));
}
}, 1000);
});
};
// Using .then/.catch (older pattern)
fetchMenu(1)
.then(menu => console.log('Menu:', menu))
.catch(err => console.error(err.message));
async/await — The Modern Way
JavaScript
// 🏢 INDUSTRY STANDARD: async/await replaces .then() chains
const loadRestaurants = async () => {
try {
// fetch() returns a Promise — await pauses until it resolves
const response = await fetch('https://api.example.com/restaurants');
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const data = await response.json(); // Parse JSON body
console.log('Restaurants:', data);
return data;
} catch (error) {
console.error('Failed to load:', error.message);
}
};
loadRestaurants(); // Call the async function
// ═══ REAL-WORLD EXAMPLE: POST request with JSON body ═══
const placeOrder = async (orderData) => {
const response = await fetch('/api/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(orderData),
});
return await response.json();
};
Popup Boxes — alert, confirm, prompt
JavaScript
// alert — Display message (blocks execution)
alert('Order placed successfully!');
// confirm — Yes/No dialog (returns boolean)
const proceed = confirm('Are you sure you want to cancel?');
if (proceed) cancelOrder();
// prompt — Input dialog (returns string or null)
const name = prompt('Enter your name:', 'Guest');
console.log(`Welcome, ${name}!`);
alert(), confirm(), prompt() — These block the main thread and provide terrible UX. In production, use custom modal components (like Razorpay's payment dialog). These are only for debugging and learning exercises.3.10 Local Storage & Session Storage
JavaScript
// 🏢 Used at Flipkart for cart persistence, at CRED for theme preference
// ═══ localStorage — persists even after browser closes ═══
// Store a simple value
localStorage.setItem('theme', 'dark');
// Retrieve a value
const theme = localStorage.getItem('theme'); // 'dark'
// Store an object (must stringify!)
const cart = [
{ id: 1, name: 'Biryani', qty: 2 },
{ id: 2, name: 'Naan', qty: 4 }
];
localStorage.setItem('cart', JSON.stringify(cart));
// Retrieve and parse
const savedCart = JSON.parse(localStorage.getItem('cart')) || [];
// Remove a specific item
localStorage.removeItem('theme');
// Clear ALL localStorage
localStorage.clear();
// ═══ sessionStorage — same API, but data clears when tab closes ═══
sessionStorage.setItem('searchQuery', 'biryani near me');
// ═══ Date & Math objects ═══
const now = new Date();
console.log(now.toLocaleDateString('en-IN')); // '22/06/2025'
console.log(now.toLocaleTimeString('en-IN')); // '10:30:00 am'
console.log(Date.now()); // Timestamp in ms
console.log(Math.random()); // 0 to 0.999...
console.log(Math.floor(Math.random() * 100)); // Random 0–99
console.log(Math.max(10, 25, 5)); // 25
console.log(Math.round(4.7)); // 5
| Feature | localStorage | sessionStorage |
|---|---|---|
| Persistence | Until manually cleared | Until tab/window closes |
| Scope | All tabs on same origin | Only the current tab |
| Size limit | ~5–10 MB | ~5–10 MB |
| Use case | Theme, cart, user preferences | Search filters, form drafts |
Industry Problems — JavaScript in the Real World
🏢 Case Study 1: Swiggy's Real-Time Search
The Problem: When a user types "biryani" in the search bar, results must appear instantly without a full page reload. The search must debounce (wait 300ms after the user stops typing before making an API call) to avoid flooding the server with requests.
The JavaScript Solution:
JavaScript
// 🏢 Debounced Search — Swiggy-style
let debounceTimer;
const searchRestaurants = async (query) => {
if (query.length < 2) return;
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
const data = await res.json();
renderResults(data.restaurants);
} catch (err) {
console.error('Search failed:', err);
}
};
searchInput.addEventListener('input', (e) => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
searchRestaurants(e.target.value);
}, 300); // Wait 300ms after user stops typing
});
Key Concepts Used: async/await, fetch(), addEventListener, setTimeout, template literals, arrow functions.
🏢 Case Study 2: Flipkart's Cart with localStorage
The Problem: Users add items to their cart, then close the browser. When they return hours later, their cart should still be there. No login required.
The JavaScript Solution:
JavaScript
// 🏢 Persistent Cart — Flipkart-style
const CART_KEY = 'flipkart_cart';
const getCart = () => {
return JSON.parse(localStorage.getItem(CART_KEY)) || [];
};
const saveCart = (cart) => {
localStorage.setItem(CART_KEY, JSON.stringify(cart));
};
const addToCart = (product) => {
const cart = getCart();
const existing = cart.find(item => item.id === product.id);
if (existing) {
existing.qty += 1;
} else {
cart.push({ ...product, qty: 1 });
}
saveCart(cart);
updateCartUI(cart);
};
const getCartTotal = () => {
const cart = getCart();
return cart.reduce((sum, item) => sum + (item.price * item.qty), 0);
};
Key Concepts Used: localStorage, JSON.stringify/parse, spread operator, Array.find(), Array.reduce(), arrow functions.
🏢 Case Study 3: Razorpay's Payment Status Polling
The Problem: After a user initiates a UPI payment, Razorpay needs to poll the server every 3 seconds to check if the payment was completed, failed, or is still pending. After 60 seconds, stop polling and show a timeout message.
The JavaScript Solution:
JavaScript
// 🏢 Payment Polling — Razorpay-style
const pollPaymentStatus = async (paymentId) => {
const MAX_ATTEMPTS = 20; // 20 × 3s = 60 seconds
let attempts = 0;
return new Promise((resolve, reject) => {
const timer = setInterval(async () => {
attempts++;
try {
const res = await fetch(`/api/payments/${paymentId}/status`);
const { status } = await res.json();
if (status === 'success') {
clearInterval(timer);
resolve('Payment successful! ✅');
} else if (status === 'failed') {
clearInterval(timer);
reject(new Error('Payment failed ❌'));
}
} catch (err) {
console.warn('Poll error, retrying...');
}
if (attempts >= MAX_ATTEMPTS) {
clearInterval(timer);
reject(new Error('Payment timed out ⏰'));
}
}, 3000);
});
};
Key Concepts Used: async/await, Promises, setInterval/clearInterval, fetch(), destructuring, template literals, error handling.
Lab Exercises — Hands-On Practice
Lab 1: Variables, Data Types & Operators — Console Drill
Objective: Master let/const, data types, type coercion, and operators through Console-based exercises.
Instructions:
- Open Chrome DevTools Console (F12 → Console).
- Declare a
constobject for a student with: name, age, branch, CGPA, isPlaced. - Demonstrate the difference between
==and===with 5 examples (each showing a different coercion trap). - Write expressions using
??(nullish coalescing) and?.(optional chaining) — show when they differ from||. - Calculate a product's final price: MRP ₹999, discount 15%, GST 18%. Use
constfor all values. Use template literals to format the output as:"MRP: ₹999 | Discount: ₹149.85 | GST: ₹152.85 | Final: ₹1,002.00". - Use
typeofto check 8 different values and log the results in a table usingconsole.table().
Lab 2: Functions & ES6 Features — Utility Module
Objective: Build a utility module using arrow functions, destructuring, spread/rest, and template literals.
Requirements:
- Create
utils.jswith the following exported functions (all arrow functions):formatINR(amount)→ returns"₹1,23,456"format usingtoLocaleString('en-IN')calcGST(price, rate = 0.18)→ returns{ base, gst, total }createUser({ name, email, role = 'student' })→ uses destructuring in parametersmergeConfig(defaults, ...overrides)→ uses rest + spread to merge objectstruncate(text, maxLength = 50)→ truncates with "..." if too long
- Create
app.jsthat imports all functions and demonstrates each one. - Use
<script type="module">in your HTML.
Lab 3: Control Flow — Student Grade Calculator
Objective: Build a grade calculator using if-else, switch, loops, and array methods.
Requirements:
- Create an array of 10 student objects:
{ name, marks: [sub1, sub2, sub3, sub4, sub5] }. - For each student, calculate:
- Total marks (use
reduce()) - Average (total / subjects)
- Grade using if-else: A+ (≥90), A (≥80), B (≥70), C (≥60), F (<60)
- Pass/Fail status using
every(): fail if any subject is below 35
- Total marks (use
- Use
for...ofto iterate through students. - Use
filter()to find all students who failed. - Use
sort()to rank students by average (highest first). - Display the results in a styled HTML table using template literals.
Lab 4: Fetch API — Live Weather Dashboard
Objective: Build a weather dashboard that fetches live data from a free API using async/await.
Requirements:
- Use the free Open-Meteo API (no API key needed):
https://api.open-meteo.com/v1/forecast?latitude=28.61&longitude=77.23¤t_weather=true - Create an input field for city name and a "Get Weather" button.
- On button click, use
fetch()withasync/awaitto get weather data. - Display: temperature, wind speed, weather condition (use a
switchon weather code). - Add loading state (show a spinner while fetching).
- Handle errors with
try/catch— show a user-friendly error message if the API fails. - Save the last searched city in
localStorageand auto-load it on page refresh.
Lab 5: Complete App — To-Do List with localStorage
Objective: Build a fully functional to-do application using all JavaScript concepts from this unit.
Requirements:
- Add tasks: Input field + button. Use
addEventListener, template literals to create task HTML. - Toggle complete: Click a task to mark it done (strikethrough).
- Delete tasks: Delete button on each task.
- Filter: Three buttons — All, Active, Completed. Use
filter(). - Persist: Save all tasks to
localStorage. Load on page refresh. - Stats: Show "3 of 7 tasks completed" using
filter().length. - Clear completed: Button to remove all completed tasks.
- ES6+ only: Use
const/let, arrow functions, destructuring, template literals, spread operator, array methods (map,filter,find,findIndex). - Style with CSS from Unit 3 — dark theme, card UI, smooth transitions.
Deliverable: todo.html, todo.css, todo.js — all using ES6+ syntax.
MCQ Assessment Bank — 15 Questions
Hover over any question to reveal the answer. Each question is tagged with Bloom's Taxonomy level.
What is the output of console.log(typeof null)?
"null""undefined""object""boolean"
"object" — This is a famous JavaScript bug from its first implementation in 1995. typeof null returns "object" due to a low-level type tag error. It has never been fixed because too much existing code depends on it.What is the difference between let and var?
letis function-scoped,varis block-scopedletis block-scoped,varis function-scoped- There is no difference
letcannot be reassigned
let is block-scoped (confined to the {} block where it's declared), var is function-scoped (accessible throughout the entire function). Option D describes const, not let.What is the output of '5' + 3?
8"53""8"NaN
"53" — The + operator, when one operand is a string, performs string concatenation. '5' + 3 converts 3 to "3" and concatenates to "53". Note: '5' - 3 would give 2 (numeric subtraction).Which keyword should you use by default for declaring variables in modern JavaScript?
varletconstdefine
const — Industry best practice: use const by default (prevents accidental reassignment). Use let only when you need to reassign. Never use var — it's legacy ES5.What does the ?? (nullish coalescing) operator do?
- Returns right side if left side is any falsy value
- Returns right side only if left side is
nullorundefined - Performs logical AND
- Checks if a variable exists
|| which treats 0, '', and false as falsy, ?? only triggers on null or undefined. Example: 0 ?? 10 returns 0, but 0 || 10 returns 10.What is the correct syntax for an arrow function that takes two parameters and returns their sum?
const add = (a, b) => a + b;const add = (a, b) -> a + b;const add = function(a, b) => a + b;const add = a, b => a + b;
=> (fat arrow). Multiple parameters need parentheses (a, b). Single-expression body has implicit return (no {} or return needed). Option B is Java/Kotlin syntax.What does const { name, age } = student; do?
- Creates a new object with
nameandageproperties - Extracts
nameandagefromstudentinto separate variables - Deletes
nameandagefromstudent - Checks if
studenthasnameandage
student and creates local const variables name and age. The original object is not modified.Which loop should you use to iterate over the VALUES of an array?
for...infor...ofwhileforEachonly
for...of — Iterates over values of iterables (arrays, strings, Maps, Sets). for...in iterates over keys/indices and is designed for objects. Using for...in on arrays can include inherited properties — avoid it for arrays.What does fetch() return?
- The response data directly
- A Promise that resolves to a Response object
- A JSON object
- An XMLHttpRequest object
fetch() returns a Promise that resolves to a Response object. You need to call .json() or .text() on the Response (which also returns a Promise) to get the actual data. That's why you see await fetch(url) then await response.json().How do you store a JavaScript object in localStorage?
localStorage.setItem('key', object)localStorage.setItem('key', JSON.stringify(object))localStorage.setObject('key', object)localStorage.key = object
localStorage only stores strings. You must convert objects to JSON strings with JSON.stringify() before storing, and parse them back with JSON.parse() when retrieving. Option A would store "[object Object]".What is the output of: for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); }
0, 1, 23, 3, 3undefined, undefined, undefined0, 0, 0
3, 3, 3 — var is function-scoped, so there's only ONE i shared across all iterations. By the time setTimeout callbacks run (100ms later), the loop has finished and i is 3. Using let instead of var would fix this (each iteration gets its own i).Which is the correct way to handle errors with async/await?
async function f() { fetch(url).catch(e => console.log(e)); }async function f() { try { await fetch(url); } catch(e) { console.log(e); } }async function f() { if (await fetch(url) == error) console.log('error'); }async function f() { await fetch(url) || console.log('error'); }
async/await error handling is wrapping await calls in try/catch. This catches both network errors and HTTP errors (when combined with a response.ok check). Option A works but mixes .catch() with async, which is inconsistent.What does the spread operator do in const copy = { ...original, name: 'New' }?
- Creates a deep copy of
original - Creates a shallow copy of
originalwithnameoverridden - Deletes the
nameproperty fromoriginal - Throws an error — you can't spread objects
original, then overrides name with 'New'. It's shallow — nested objects are still references to the original. This pattern is heavily used in React state updates.A developer writes const x = 5; x = 10;. What happens?
xbecomes10- Nothing happens,
xstays5 TypeError: Assignment to constant variableSyntaxError
TypeError — const prevents reassignment. Once a value is assigned, it cannot be changed. This is a runtime error. Note: const obj = {}; obj.key = 'val'; is fine — mutation is allowed, reassignment is not.A Swiggy developer needs to choose between callbacks, Promises, and async/await for API calls. Which is the best choice for readability and maintainability?
- Callbacks — they're the simplest
- Promises with
.then().catch()— they're chainable async/await— reads like synchronous code, easiest to debug- All three are equivalent, use any
async/await — It's the industry standard because: (1) reads like synchronous code (top-to-bottom), (2) try/catch for errors is natural, (3) easier to debug in DevTools, (4) avoids "callback hell" and .then() chains. Every modern JavaScript codebase at Swiggy, Flipkart, and CRED uses async/await.Chapter Summary
🎯 Unit 4 — Key Takeaways
- Embedding: Use external
.jsfiles withdeferor at end of<body>. Never use inlineonclick. - Variables:
constby default,letwhen reassignment needed. Nevervar. - Types: 7 primitives + Object. Use
===always. Know the coercion traps ('5' + 3 = '53'). - Operators:
??(nullish coalescing),?.(optional chaining),**(exponentiation), ternary. - Control Flow:
if/else,switch,for,for...of(values),for...in(keys),while,do...while. - Functions: Arrow functions are the default. Default parameters. Implicit return for single expressions.
- ES6+: Template literals (
`Hello ${name}`), destructuring, spread/rest, modules (import/export). - Error Handling:
try/catch/finally— always wrap API calls. - Objects: Shorthand properties,
Object.keys/values/entries, computed property names. - JSON:
JSON.stringify()to convert,JSON.parse()to read. The universal API data format. - Async:
fetch()returns a Promise. Useasync/await+try/catch. Always checkresponse.ok. - Storage:
localStoragepersists across sessions.sessionStoragedies with the tab. AlwaysJSON.stringifyobjects.
📋 JavaScript ES6+ Quick Reference
// === VARIABLES ===
const x = 10; // Immutable binding (default choice)
let y = 20; // Mutable binding (when reassignment needed)
// === ARROW FUNCTIONS ===
const fn = (a, b) => a + b; // Implicit return
const fn2 = (x) => { return x * 2; }; // Explicit return
// === TEMPLATE LITERALS ===
const msg = `Hello, ${name}! Total: ₹${price}`;
// === DESTRUCTURING ===
const { a, b } = obj; // Object
const [x, y, ...rest] = arr; // Array
// === SPREAD / REST ===
const merged = { ...obj1, ...obj2 }; // Spread
const sum = (...nums) => nums.reduce((a,b) => a+b); // Rest
// === FETCH + ASYNC/AWAIT ===
const getData = async () => {
try {
const res = await fetch(url);
const data = await res.json();
} catch (e) { console.error(e); }
};
// === LOCALSTORAGE ===
localStorage.setItem('key', JSON.stringify(obj));
const data = JSON.parse(localStorage.getItem('key'));
Interview Preparation — JavaScript Questions That Companies Ask
These are real questions asked at TCS, Infosys, Wipro, Accenture, Flipkart, Swiggy, and startup interviews.
Q1: What is the difference between == and === in JavaScript?
Model Answer:
== (loose equality) performs type coercion before comparison. It converts operands to the same type, which leads to surprising results: 5 == '5' is true, 0 == false is true, null == undefined is true.
=== (strict equality) compares both value AND type without any coercion. 5 === '5' is false because a number is not a string.
In industry, we always use ===. ESLint rules at Flipkart and Swiggy enforce this. == is a bug waiting to happen.
Q2: Explain var vs let vs const. Which should you use?
Model Answer:
var: Function-scoped, hoisted asundefined, can be redeclared. Legacy — never use in modern code.let: Block-scoped, not hoisted (Temporal Dead Zone), cannot be redeclared. Use when the value will change.const: Block-scoped, not hoisted, cannot be reassigned or redeclared. Use as the default choice.
The rule is: const first, let when you need to reassign, var never. const communicates intent — "this binding won't change" — making code easier to reason about.
Important: const prevents reassignment, not mutation. const arr = []; arr.push(1); works fine.
Q3: What are Promises? How does async/await improve on .then() chains?
Model Answer:
A Promise represents a value that will be available in the future. It has three states: pending, fulfilled (resolved), or rejected. Promises solve "callback hell" by allowing chainable .then() and .catch().
async/await is syntactic sugar over Promises. It makes asynchronous code read like synchronous code:
// .then() chain — harder to read
fetch(url).then(r => r.json()).then(data => process(data)).catch(err => handle(err));
// async/await — reads top-to-bottom
const r = await fetch(url);
const data = await r.json();
process(data);
Key benefits: (1) more readable, (2) natural error handling with try/catch, (3) easier debugging — you can set breakpoints on each await line.
Q4: Explain destructuring with a real-world example.
Model Answer:
Destructuring extracts values from objects and arrays into standalone variables. Real-world example — an API response:
// API returns a user object
const response = { id: 42, name: 'Priya', email: 'priya@example.com', role: 'admin' };
// Without destructuring — verbose
const name = response.name;
const email = response.email;
// With destructuring — clean
const { name, email, role } = response;
// In function parameters (very common in React)
const UserCard = ({ name, email, role = 'user' }) => { /* ... */ };
Array destructuring is useful for swap ([a, b] = [b, a]) and for functions returning multiple values.
Q5: What is the difference between localStorage and sessionStorage?
Model Answer:
| Feature | localStorage | sessionStorage |
|---|---|---|
| Persistence | Permanent — survives browser close | Temporary — cleared when tab closes |
| Scope | Shared across all tabs on same origin | Isolated to the current tab |
| Use cases | Cart, theme, auth tokens, preferences | Search filters, form drafts, temp state |
Both share the same API (setItem, getItem, removeItem, clear) and store only strings (so you must JSON.stringify objects). Size limit is ~5-10MB per origin.
Real example: Flipkart uses localStorage for cart persistence and sessionStorage for the current search session's filters.