JS
JavaScript · Unit 2
Full Stack Web Development · UI24PC520CS
Unit 2 · Full Stack Web Development · UI24PC520CS

JavaScript

Sixteen modules that take you from an empty VS Code window to a page that validates a form, answers a click and rewrites itself — with every single line running in front of you, next to the code that made it. No prior JavaScript assumed. None at all.

ES6VariablesFunctionsObjectsArraysStringsEventsValidationDOM
8syllabus topics
22past questions
71chunks
9.4hours, over 5 sittings
How do you want to read this?
You can switch inside any module at any time. Whatever you pick here becomes the starting point.
This form is real. Watch JavaScript check it — then type in it yourself.
starting…
Module 9 teaches you to write this. Module 10 covers every rule the exam has ever asked for.
The same page, changing itself — nothing here reloadsauto
Your cart is empty
starting…Total ₹0

The syllabus, and where each line is taught

JavaScript: Introduction to JavaScript ES6, Variables, Objects, Document and Window Objects, Arrays, String Manipulation, Scripting Functions, Event Handling.
Introduction to JavaScript ES6M0, M3
VariablesM3
ObjectsM5
Document and Window ObjectsM11, M12
ArraysM6
String ManipulationM7
Scripting FunctionsM4
Event HandlingM8

The modules

00
Why JavaScript Existsready
7 chunks · 0:00 – 0:40
7 chunks · 0:00 – 0:40
A notice board you have all waited in front of0:00 – 0:06
The man who had ten days0:06 – 0:12
From ten days to everywhere, and across the MERN stack0:12 – 0:18
What examiners ask, and where you will learn it0:18 – 0:23
Three languages, three jobs0:23 – 0:29
What actually happens when a page loads0:29 – 0:35
Java and JavaScript, since you have just done Java0:35 – 0:40
01
The File, The Skeleton, The Editorready
6 chunks · 0:00 – 0:40
6 chunks · 0:00 – 0:40
Making something from nothing0:00 – 0:07
The skeleton, tag by tag0:07 – 0:15
Running it, and the moment Live Server earns its keep0:15 – 0:22
Head or body? Let us break it on purpose0:22 – 0:29
A starter set of styles, and what each page takes from it0:29 – 0:36
Your project so far, and practice0:36 – 0:40
02
First Script, First Output, The Consoleready
4 chunks · 0:00 – 0:32
4 chunks · 0:00 – 0:32
Where the script tag goes, and what breaks0:00 – 0:08
Four ways to show something0:08 – 0:17
The console, and reading your first error0:17 – 0:25
A page that changes when you click it, and practice0:25 – 0:32
03
Variables, Data Types, let vs constready
5 chunks · 0:00 – 0:38
5 chunks · 0:00 – 0:38
A variable is a labelled box0:00 – 0:07
The types JavaScript has0:07 – 0:15
let and const, and why var is broken0:15 – 0:25
Template literals, and joining text0:25 – 0:32
Checkpoint and practice0:32 – 0:38
04
Functions and Arrow Functionsready
4 chunks · 0:00 – 0:38
4 chunks · 0:00 – 0:38
A function is a recipe you can run again0:00 – 0:09
Three ways to write the same function0:09 – 0:18
Arrow functions in full, with defaults and rest0:18 – 0:30
Checkpoint and practice0:30 – 0:38
05
Objectsready
4 chunks · 0:00 – 0:35
4 chunks · 0:00 – 0:35
An object is a labelled drawer0:00 – 0:08
Adding, changing and removing properties0:08 – 0:17
Methods, shorthand, unpacking, and an object holding a list0:17 – 0:28
Checkpoint and practice0:28 – 0:35
06
Arrays and Array Methodsready
5 chunks · 0:00 – 0:42
5 chunks · 0:00 – 0:42
An array is a numbered shelf0:00 – 0:08
Adding and removing along the shelf0:08 – 0:16
sort, and the trap everybody falls into0:16 – 0:25
forEach against map, then filter, find and reduce0:25 – 0:36
Checkpoint and practice0:36 – 0:42
07
String Manipulationready
4 chunks · 0:00 – 0:36
4 chunks · 0:00 – 0:36
A string is a row of characters0:00 – 0:08
The methods the papers actually use0:08 – 0:17
Building a full name, pulling out a title0:17 – 0:28
Checkpoint and practice0:28 – 0:36
08
Events and Event Handlingready
4 chunks · 0:00 – 0:34
4 chunks · 0:00 – 0:34
An event is a doorbell you install and forget0:00 – 0:08
Three ways to attach, and which one wins0:08 – 0:17
The events this unit needs, and the event object0:17 – 0:27
Checkpoint and practice0:27 – 0:34
09
Form Validation — Foundationsready
5 chunks · 0:00 – 0:40
5 chunks · 0:00 – 0:40
Why validate at all0:00 – 0:07
Read a field, show an error, clear it0:07 – 0:15
Password and re-type password0:15 – 0:24
A full name built as you leave the field0:24 – 0:32
Patterns, gently, and practice0:32 – 0:40
10
Form Validation — Every PYQ Patternready
5 chunks · 0:00 – 0:40
5 chunks · 0:00 – 0:40
One form, five rules, built field by field0:00 – 0:07
Email, two different rule sets0:07 – 0:15
Date of birth and age, and pincode0:15 – 0:24
Usernames, and counting checkboxes0:24 – 0:33
Checkpoint and practice0:33 – 0:40
11
The DOM — Document Objectready
5 chunks · 0:00 – 0:42
5 chunks · 0:00 – 0:42
The page as a tree you can rearrange0:00 – 0:08
Finding elements, five ways0:08 – 0:16
Changing what is already there0:16 – 0:25
Making new elements and removing them0:25 – 0:34
A calculator with one text box, and practice0:34 – 0:42
12
The Window Objectready
3 chunks · 0:00 – 0:26
3 chunks · 0:00 – 0:26
The window is the room the page sits in0:00 – 0:08
alert, confirm, prompt, and timers0:08 – 0:18
Load order, and why it bit you in Module 20:18 – 0:26
13
Quirks, Coercion and Legacy JSready
4 chunks · 0:00 – 0:32
4 chunks · 0:00 – 0:32
Truthy and falsy0:00 – 0:08
== against ===, and the empty array question0:08 – 0:17
Hoisting, and what let changed0:17 – 0:25
with, and why it is banned0:25 – 0:32
14
ES6 Bridge + Unit Recapready
3 chunks · 0:00 – 0:26
3 chunks · 0:00 – 0:26
Classes, modules, promises: the bridge to Units 3 and 40:00 – 0:10
One card per syllabus topic0:10 – 0:19
The whole project, and JavaScript across MERN0:19 – 0:26
15
Timed Self-Assessment + Answer Keyready
3 chunks · 0:00 – 0:22
3 chunks · 0:00 – 0:22
Eight questions, ten minutes0:00 – 0:09
Worked solutions0:09 – 0:16
All twenty-two past questions, in one place0:16 – 0:22
Course Instructor
K TRISHAANK
Department of Computer Science & Engineering
Vasavi College of Engineering (Autonomous)
Ibrahimbagh, Hyderabad – 500 031
UI24PC520CS · Unit 2 · R-24 · A.Y. 2026–27
Module 0 · Why JavaScript Exists · 40 min
CHUNK 1 OF 7 0:00 – 0:06

Before we write a single line

This module opens the syllabus phrase Introduction to JavaScript ES6 — where the language came from, why it looks the way it does, and what ES6 changed. Modules 3 and 4 cover the ES6 features themselves.
Nothing to type on this page. Sit back. This is the twenty minutes that makes the other eight hours make sense — and by Module 2 you will have a web page doing something you told it to do.

A notice board you have all waited in front of

Picture the college notice board — the physical one. To see if anything changed, you walk over and look. If nothing changed, you walked for nothing.

The web worked exactly like that until 1995. You filled a form, pressed submit, and the entire page went away and came back. Wrong pincode? The whole page reloads to tell you. Every field you typed, gone.

WITHOUT JAVASCRIPT · 1994 Submit submit blank the page is gone server Pincode must be 6 digits everything you typed — gone and round again WITH JAVASCRIPT · TODAY Pincode must be 6 digits ↑ appeared as you typed. No reload. fix it looks good submit Done the page never went away
The same form, thirty years apart · the difference is one language
JavaScript lets a page change without going away and coming back.
Everything else in this unit is a detail of that one idea.

Every “Add to cart” that updates the number in the corner, every search box that suggests as you type, every form that turns a field red before you submit — all of it is the thing you are about to learn.

CHUNK 2 OF 7 0:06 – 0:12

The man who had ten days

Brendan Eich, who created JavaScript at Netscape in 1995
Brendan Eich
Created JavaScript · Netscape, 1995
  • Hired by Netscape in 1995 to put a scripting language inside their browser.
  • Given ten days to build a working prototype. Ten. Not ten weeks.
  • Designed it as a small, friendly language for people who were not programmers.
  • Later co-founded Mozilla and became its CEO — the people who make Firefox.

Why is it called JavaScript if it has nothing to do with Java?

Because of marketing. In 1995 Java was the exciting thing, and Netscape had a deal with Sun, the company that owned Java. The language was called Mocha, then LiveScript, and then — three months before release — renamed JavaScript to ride Java's popularity.

Java and JavaScript are not related. Not versions of each other, not made by the same people, not similar underneath. The classic line: Java is to JavaScript as car is to carpet. If an examiner asks, that is the answer — and you have just finished a whole unit of Java, so you are unusually well placed to see how different they are.
Hold on to the ten days. Later in this unit you will meet a few things in JavaScript that look plainly wrong — a check that says an empty list is both true and false, a type called null that reports itself as an object. Every one of them traces back to a decision made in a hurry in 1995, and by then the whole web was using it and it was too late to fix. Module 13 is built entirely out of these, and the exam asks about them every single year.
CHUNK 3 OF 7 0:12 – 0:18

From ten days to everywhere

1995 born in ten days 1997 becomes ECMAScript the official name 2009 Node.js — JavaScript leaves the browser YOUR UNIT 4 2013 React arrives YOUR UNIT 3 2015 ES6 let · const · arrows YOUR SYLLABUS now every browser
Thirty years · two of these dots are units you have not taken yet

Where this unit sits in your course

Your course is called Full Stack Web Development, and the stack is MERN. Here is the thing worth noticing:

MongoDB the database Express the server framework React the interface Node.js runs all of it JS All four are JavaScript — one language, top to bottom
The whole point of MERN · and why this unit is the floor the others stand on
All four letters are JavaScript. That is the entire point of the MERN stack — one language from the database to the button the user clicks. Which means this unit is not one topic of five. It is the floor the other four units stand on. Time spent here pays back three more times.
CHUNK 4 OF 7 0:18 – 0:23

What examiners ask, and where you will learn it

I read the last four question papers. The topics are not spread evenly — some come up almost every time, and those are the ones this course spends its hours on.

Theme
How often
Where you will learn it
Form validation
7 questions
Modules 9 and 10
Changing the page (DOM)
4 questions
Module 11
Arrays
4 questions
Module 6
Strings
3 questions
Module 7
Objects
3 questions
Module 5
Odd outputs
2 questions
Module 13
In this course
22 past questions
every one answered with code that runs
One promise about how this works. Every piece of code in the next nine hours runs in front of you. Not a screenshot, not “this would display” — the real page, doing the real thing, next to the code that made it. When something breaks, you will see it break, and you will see why. That includes the mistakes. Everyone makes them, and reading an error message calmly is half of what a programmer does.
CHUNK 5 OF 7 0:23 – 0:29

Three languages, three jobs

A web page is built from three languages, and students lose marks every year by mixing up which does what. The division is clean once you see it.
HTML
Says what exists. A heading, a text box, a button. It cannot decide anything and it cannot change after the page has loaded.
CSS
Says what it looks like. Colour, spacing, borders, layout. It can respond to screen size, but it cannot test what somebody typed.
JavaScript
Says what happens. It can hold a value, compare two things, decide, repeat, and change the page after it has loaded. It is the only one of the three that can do any of that.
ONE FORM · THREE LAYERS, ADDED IN ORDER HTML what exists Email Password Sign in plain, unstyled, inert + CSS how it looks Email Password Sign in handsome — and still inert JS + JavaScript what happens Email Password Needs 8 characters Sign in it checks, decides, responds structure presentation behaviour
The three words an examiner is looking for · structure, presentation, behaviour
Question
HTML
CSS
Answers
What is on the page?
What does it look like?
Is it a programming language?
No — a markup language
No — a style sheet language
Can it make a decision?
No
Almost none
Runs when?
as the page is read
as the page is drawn
In our form
<input> exists
it has a rounded border
HTML says what exists. CSS says how it looks.
JavaScript says what happens.
Exam wording to keep. “HTML provides structure, CSS provides presentation, JavaScript provides behaviour.” Those three nouns are the ones markers look for.
CHUNK 6 OF 7 0:29 – 0:35

What actually happens when a page loads

You type an address, press enter, and a page appears. Five things happen in between, and knowing them makes Module 11 familiar instead of mysterious.

the file index.html plain text, nothing more read the browser parses it, tag by tag it builds a tree in memory the DOM html head body a live tree of objects JS your script changes the tree and the page redraws no reload — the same tree, edited
File → the browser reads it → a tree in memory → your script edits the tree
The file on disk is dead text. It never changes. Your JavaScript does not edit the file — and that surprises almost everyone the first time.
The browser builds a tree of objects from it. That tree lives in memory, not on disk. It has a name, and you will meet it properly in Module 11.
JavaScript changes the tree, and the browser redraws. That is every page-changing question in every paper, in one sentence.
Refresh and your changes vanish, because the file was never touched. Keeping them for real needs a database — which is Unit 4.
The mistake this explains in advance. If your script runs before the browser has finished building the tree, the element you are looking for does not exist yet and you get null. That is the most common first error in JavaScript, and Module 2 shows it happening on purpose so it never confuses you.
CHUNK 7 OF 7 0:35 – 0:40

Java and JavaScript, since you have just done Java

You finished a whole unit of Java. That is an advantage here, and a trap. The names are similar and a few things look alike, but underneath they are different in ways that get examined.

Java
JavaScript
Made by
Sun Microsystems, 1995
Netscape, 1995 — unrelated teams
Before it runs
Compiled by javac into bytecode
Interpreted — the browser reads the text and runs it
Runs inside
the JVM
the browser (or Node, in Unit 4)
Types
Staticint x = 5; and x is forever a number
Dynamiclet x = 5; then x = "five" is allowed
Errors appear
at compile time, before you run
at run time, often in the console
A file must
match the public class name
be named anything you like
In our code
public static void main is the way in
there is no main — the script runs, top to bottom
The one that will catch you. Java told you off at compile time. JavaScript will not. A misspelled variable name is a perfectly legal JavaScript program — it quietly does the wrong thing at run time. This is why the browser console matters so much, and why Module 2 teaches it before anything else.

Check yourself

1. A page shows a red error under a field the moment you type. Which of the three languages is doing that, and why can it not be the other two?
2. You change a heading with JavaScript, then press refresh. The old heading is back. Why?
3. Name one thing Java checks that JavaScript will not.

Show the answers
1. JavaScript. HTML can only say the field exists; CSS can only say what it looks like. Neither can test what you typed and decide to show a message. Deciding is programming, and JavaScript is the only programming language of the three.

2. Because the file never changed. Your script edited the DOM — the tree the browser holds in memory. Refreshing throws that tree away and builds a fresh one from the file on disk, which still says what it always said.

3. Types, spelling, and whether a method exists. javac refuses to build a program with a misspelled variable. JavaScript runs it happily and goes wrong later. That trade — freedom now, mistakes later — is the single biggest difference in how the two languages feel.

Carry forward: Module 1 opens VS Code and makes a file from nothing. Module 2 puts the first script in it and opens the console you are going to live in.

Nothing to save yet — but here is where it all goes

FSWD-Unit2 ← make this folder before Module 1 ├── 01-skeleton ├── 02-first-script ├── 03-variables └── … one folder per module, to Module 14

Module 0 writes no code — it is the twenty minutes that makes the rest make sense. From Module 1 onward every chunk adds a file, and this tree is redrawn at the end of each module so you always know where you are.

Module 1 · The File, The Skeleton, The Editor · 40 min
CHUNK 1 OF 6 0:00 – 0:07

Making something from nothing

Everything in this unit lives in a file you create yourself. This chunk makes the first one.
Module 0 ended on a promise: the browser reads a file and builds a page from it. This is that file. Nothing here is JavaScript yet — it is the thing JavaScript will later reach into.
Open VS Code. You are looking at an empty window. In about ninety seconds there will be a page in your browser with your name on it.
Make a folder first. Anywhere you like — Desktop is fine. Call it FSWD-Unit2. Inside it, another called 01-skeleton. Every module in this course gets its own folder, and by Module 15 you will have a real project.
In VS Code: FileOpen Folder → pick FSWD-Unit2. The Explorer panel on the left is now your project.
New file: Ctrl + N.
Save it straight away: Ctrl + S. Navigate into 01-skeleton and type the name with the extension: index.html
The extension is the whole trick. Save it as index and VS Code treats it as plain text — no colours, no autocomplete, and the browser will show it as text rather than a page. Save it as index.html and everything wakes up. If your file looks grey and lifeless, this is why.
Why index.html and not page.html? index.html is the name every web server looks for by default. Open a folder and the server serves index.html without being asked. Any name works while you are learning — but this is the habit that matters later.

This is what you should be looking at

index.html — FSWD-Unit2 — Visual Studio Code
EXPLORER
FSWD-Unit2
01-skeleton
index.html
index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4</head>
5<body>
6</body>
7</html>
Go LiveLn 7, Col 1HTMLUTF-8

Folder on the left, file open in the middle, blue bar along the bottom with Go Live on the right. If your window looks like this, you are ready.

CHUNK 2 OF 6 0:07 – 0:15

The skeleton, tag by tag

Every HTML page has the same bones. Think of a house: the foundation, then the walls, then the rooms. You never skip one.
FSWD-Unit2 / 01-skeleton / index.html
the wrapper1<!DOCTYPE html>
2<html lang="en">
the head — invisible3<head>
4 <meta charset="utf-8">
5 <title>My first page</title>
6</head>
the body — all you see7<body>
8
9 <h1>Hello from Vasavi</h1>
10
11</body>
12</html>
untitled×
127.0.0.1:5500/index.html
live
the page builds as the code does
You do not have to type all of that. In an empty .html file, type a single ! and press Tab. VS Code writes the whole skeleton for you. Type it out by hand once so you know what it made — then use ! forever after.

What each line is actually for

Line
What it does
Leave it out and…
<!DOCTYPE html>
Tells the browser “this is modern HTML”
the browser guesses, and older rules apply
<html lang="en">
Wraps everything; names the language
the browser has to guess the language
<head>
Information about the page
nowhere to put the title or the styles
<meta charset>
Sets how characters are stored
Telugu, Hindi and accented letters come out as symbols
<title>
The browser tab caption
the tab shows the file path
<body>
Everything the visitor sees
a blank white page
In our page
<h1> lives in the body
that is why it is the only thing on screen
<head>Things about the page. The title, how characters are stored, the styles. None of it is visible.
<body>Things on the page. Headings, forms, buttons, images. All of it is visible.
When your script does nothing and you cannot see why,
check which one it landed in.
CHUNK 3 OF 6 0:15 – 0:22

Running it — and the moment Live Server earns its keep

Right-click anywhere in the editorOpen with Live Server. Or click Go Live in the blue bar at the bottom-right.
Your browser opens at 127.0.0.1:5500/01-skeleton/index.html.
Now change the heading text and press Ctrl + S. Watch the browser. You did not refresh it.
VS Code you press Ctrl + S LIVE SERVER notices the file changed 127.0.0.1:5500 Hello from Vasavi reloads by itself edit → save → see it · all day
Save and the page updates · you will do this a few thousand times
Edit. Save. Look.
No compiling, no build step, no waiting — there is no javac here.

Why not double-click the file?

You can, and it opens. But look at the address bar — it says file:///C:/Users/... instead of 127.0.0.1:5500. That difference matters later: some things a browser can do over http are blocked over file. Getting into the Live Server habit now saves a confusing hour in Unit 4.

CHUNK 4 OF 6 0:22 – 0:29

Head or body? Let us break it on purpose

Rules stick better when you have seen them broken. Here is the same heading written twice — once in the head, once in the body.

index.html  — deliberately wrongruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Where things go</title>
6 <h1>I am in the head</h1>
7</head>
8<body>
9 <h1>I am in the body</h1>
10</body>
11</html>
untitled×
127.0.0.1:5500/index.html
live
watch line 6 arrive and change nothing
Look at the frame. “I am in the head” is nowhere. The browser did not complain, did not show an error, did not warn you. It quietly moved on. That silence is the thing to get used to — HTML almost never tells you off. It does something you did not intend.
The browser reads top to bottom. By the time it reaches your heading in the head, it has not built the body yet.
A heading in the head is not content, so there is nowhere on the page for it to go. The browser drops it and says nothing.
Where your script goes decides whether it works. A script in the head runs before the body exists, so it cannot find your button. Module 2 shows that failure happening and the two ways round it.
CHUNK 5 OF 6 0:29 – 0:36

A starter set of styles — take what each page needs

This course is about JavaScript, not CSS. But most exam questions involve a form, and an unstyled form is hard to read from the back of a room. So here are five rules, one line each — a starter set. Later pages take whichever of them they need and leave the rest out. Nothing nested, nothing clever, nothing to memorise.
FSWD-Unit2 / 01-skeleton / order.html
the head1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Canteen order</title>
five style rules6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 label { display: block; margin-bottom: 12px; }
9 input { padding: 8px; width: 200px; }
10 button { padding: 8px 16px; background: skyblue; }
11 .error { color: red; }
12 </style>
13</head>
the form14<body>
15 <h2>Canteen order</h2>
16
17 <label>Your name</label>
18 <input id="who">
19
20 <button id="go">Place order</button>
21
22 <p id="msg" class="error"></p>
23</body>
24</html>
untitled×
127.0.0.1:5500/index.html
live
the form appears piece by piece, exactly as you type it

What each rule does, and why it is here

Rule
What it does
Why we want it
body
Sets the font and stops the page going full width
a 1400px-wide form is unreadable
label
display: block puts each label on its own line
without it, everything runs together
input
Gives the boxes room to breathe
the default box is tiny
button
Makes it look pressable
students click what looks clickable
.error
Red text — and nothing else
this one matters. Every validation answer puts its message here
The dot in .error is the only new punctuation here. A plain word like button styles every button on the page. A word with a dot in front styles only the elements you have marked with class="error". That is the whole difference, and it is all the CSS you need for this unit.
<style> goes in the head, because it is information about the page rather than content on it. Same rule as always.
Every element we will script has an idwho, go, msg. That is the handle JavaScript grabs it by. Give things ids from the start and your life gets easier.
The empty <p id="msg"> is deliberate. It sits there doing nothing until JavaScript puts a message in it. Almost every validation answer in the papers uses exactly this.
You will not see all five on every page. A page with no form does not need the input rule; a page with no error message does not need .error. Later modules show a <style> block with two or three of these rules in it — that is not a different stylesheet, it is this one with the unused lines removed. Keep the full five somewhere you can copy from.
HTML made the button. CSS made it blue.
Neither can make it do anything — that starts next module.
CHUNK 6 OF 6 0:36 – 0:40

Your project so far

FSWD-Unit2 └── 01-skeleton ├── index.html new └── order.html new

Two files. By Module 15 this tree has fifteen folders and around forty files, and every one of them runs.

Practice

1Make a folder 02-practice and a file bus.html inside it. Build a page titled Bus pass with a heading, two text boxes labelled Roll number and Route, and a button reading Apply. Run it with Live Server.
Show the solution
FSWD-Unit2 / 02-practice / bus.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Bus pass</title>
6</head>
7<body>
8 <h2>Bus pass application</h2>
9 <label>Roll number <input type="text"></label>
10 <label>Route <input type="text"></label>
11 <button>Apply</button>
12</body>
13</html>
untitled×
127.0.0.1:5500/index.html
live
Two things worth noticing. Wrapping the <input> inside the <label> means clicking the words focuses the box — free, and better for everyone. And the button still does nothing, which is still correct.
2A friend’s page opens in the browser but shows the raw text <h1>Hello</h1> instead of a heading. Give two possible reasons.
Show the solution
One — the file is not saved as .html. Saved as page or page.txt, the browser treats it as plain text and prints the tags instead of obeying them. Check the tab in VS Code: no syntax colours means no .html.

Two — the <!DOCTYPE html> line is missing or misspelled and the page is being read in a legacy mode. Less likely than the first, but worth a look.

How to tell them apart in five seconds: look at the VS Code tab. No colours, reason one.
3You put <p>Welcome</p> inside <head> and nothing appears. Explain why, in the wording an examiner would want.
Show the solution
The head contains information about the document; the body contains the content that is rendered. A paragraph in the head is not part of the rendered content, so the browser does not display it — and raises no error.

The marks are in the two phrases: information about the document versus rendered content.
You can now build a page from an empty folder and run it. Every remaining module stands on that. Next: the first line of JavaScript, and the console you will spend the rest of the unit reading.
Module 2 · First Script, First Output, The Console · 32 min
CHUNK 1 OF 4 0:00 – 0:08

Your first line of JavaScript

Module 1 built a page. This one makes it do something — and shows you the mistake almost everyone makes on their first try.
JavaScript goes inside a <script> tag. Where you put that tag decides whether your code works — and getting it wrong produces no warning at all, only a page that ignores you.
SCRIPT IN THE HEAD 3 <head> 7 getElementById("box") 10 <body> 11 <p id="box"> line 7 reaches for line 11 which has not been built yet SCRIPT AT THE BOTTOM 7 <body> 8 <p id="box"> 11 getElementById("box") line 11 looks back at line 8 already built, and found the browser only reads downwards — a script reaches what is above it, never what is below
Why the very same code works in one place and not the other

The wrong way first, on purpose

01-first-script / early.html  — brokenruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Too early</title>
6 <script>
7 document.getElementById("box").innerHTML = "Hello";
8 </script>
9</head>
10<body>
11 <p id="box">waiting...</p>
12</body>
13</html>
untitled×
127.0.0.1:5500/index.html
live
the paragraph still says "waiting..." — the script did nothing
Nothing happened, and nothing complained. This is the failure Module 0 warned you about: the browser reads top to bottom, so when line 7 ran, <p id="box"> did not exist yet. The script asked for something that was not there and gave up quietly.

Move three lines and it works

01-first-script / index.html  — fixedruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Just right</title>
6</head>
7<body>
8 <p id="box">waiting...</p>
9
10 <script>
11 document.getElementById("box").innerHTML = "Hello";
12 </script>
13</body>
14</html>
untitled×
127.0.0.1:5500/index.html
live
same code, moved to the bottom of the body
The browser reads your file from the top. Everything above the script has already been built; everything below it has not.
Put the script last, inside </body>. By then the whole page exists and your code can reach any part of it.
That is the rule for this entire unit. Script at the bottom of the body. There are other ways round it, and Module 12 shows one — but you will not need it.
Script at the bottom of the body.
Nine out of ten “my code does nothing” problems are this.
CHUNK 2 OF 4 0:08 – 0:17

Four ways to show something

JavaScript can put text in four different places, and beginners mix them up constantly. Three of them are useful. One of them you should almost never use.
innerHTML
Puts text inside an element you chose. This is the one you will use for the rest of the unit, and the one every exam answer needs.
console.log
Prints in the developer console, invisible to a visitor. For checking your own work.
alert
A pop-up box that stops everything until it is dismissed. Fine for a demonstration, irritating in real use.
document.write
Writes straight into the page as it loads. Avoid it. Run it after the page has finished and it erases everything.
02-output / four.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Four ways</title>
6</head>
7<body>
8 <h2>Canteen</h2>
9 <p id="out">nothing yet</p>
10
11 <script>
12 document.write("written into the page");
13
14 document.getElementById("out").innerHTML = "put inside the paragraph";
15
16 console.log("only in the console");
17 </script>
18</body>
19</html>
untitled×
127.0.0.1:5500/index.html
live
three of the four are visible here; the fourth is in the console
JS one line of JavaScript innerHTML Canteen put inside the paragraph ↑ lands exactly where you said USE THIS console.log > only in the console a visitor never sees this. It is for you, while you work. USE THIS TOO alert This page says OK stops everything SPARINGLY document.write can wipe the page AVOID
Same instruction, four destinations · only one of them is where the visitor looks
Method
Where it lands
Use it?
innerHTML
inside the element you name
Yes — this is the workhorse
console.log
the developer console
Yes — for checking, not for users
alert
a pop-up over the page
Sparingly — the papers do use it
document.write
straight into the page
No — it can wipe the page
In our code
line 14 fills #out
that pattern is the whole of Module 11
CHUNK 3 OF 4 0:17 – 0:25

The console, and reading your first error

Java told you off before your program ran. JavaScript does not. It runs your mistake, fails halfway, and writes about it in a place you have to go and look. That place is the console, and this is the most useful eight minutes in the unit.
Open it: press F12. Or Ctrl + Shift + I. Or right-click the page → Inspect.
Click the Console tab along the top. Not Elements, not Network. Console.
Leave it open. For the rest of this unit, and the rest of your life as a web developer.

Now break something and read what it says

03-console / typo.html  — one letter wrongruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Read the error</title></head>
5<body>
6 <p id="out">nothing yet</p>
7
8 <script>
9 document.getElementById("outt").innerHTML = "Hello";
10 </script>
11</body>
12</html>
untitled×
127.0.0.1:5500/index.html
live
the page looks fine. It is not.
ElementsConsoleSourcesNetwork
✗ Uncaught TypeError: Cannot set properties of null (setting 'innerHTML')     at typo.html:9
“Cannot set properties of nullnull means nothing was found. You asked for an element and got nothing back.
“setting innerHTML — it tells you which operation failed. You were trying to put text inside something.
“at typo.html:9 — the file and the line. Click it and DevTools jumps straight there.
Put it together: line 9 asked for an element, got nothing, and could not set text on nothing. The id is outt; the paragraph is out. One letter.
An error message is not a telling-off.
It is the most specific help you will ever get — it names the file, the line and the problem.
You can type into the console too. Click beside the >, type 2 + 2, press enter. It answers. Type document.title and it tells you the page title. It is a live JavaScript scratchpad sitting inside every browser, and it costs nothing to experiment in.
CHUNK 4 OF 4 0:25 – 0:32

A page that changes when you click it

Module 1 built a button that did nothing. Here is the eight lines that give it a job — and the shape of every interactive page you will write from now on.
04-click / canteen.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Canteen</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 button { padding: 8px 16px; background: skyblue; }
9 </style>
10</head>
11<body>
12 <h2 id="head">Canteen is closed</h2>
13 <button id="go">Open it</button>
14
15 <script>
16 function openIt() {
17 document.getElementById("head").innerHTML = "Canteen is open";
18 }
19
20 document.getElementById("go").onclick = openIt;
21 </script>
22</body>
23</html>
untitled×
127.0.0.1:5500/index.html
live
press the button — the heading changes, the page does not reload
Find the thing. document.getElementById("go") hands you the button.
Say what should happen when it is clicked. .onclick = () => { ... } hands the browser a set of instructions to keep.
The instructions do not run yet. They sit there, waiting. They run only when somebody actually clicks — which is why nothing happens on load.
Inside, find another thing and change it. The heading’s innerHTML becomes new text, and the page updates. No reload.
Find it. Say what happens. Change it.
Every interactive page in this unit is that, repeated.

Your project so far

FSWD-Unit2 ├── 01-skeleton index.html · order.html ├── 02-practice bus.html └── 02-first-script ├── early.html new ├── index.html new ├── four.html new ├── typo.html new └── canteen.html new

Practice

1Build a page with a paragraph reading not shown yet and a button reading Show. Clicking the button replaces the paragraph with your roll number.
Show the solution
02-first-script / roll.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Roll number</title></head>
5<body>
6 <p id="out">not shown yet</p>
7 <button id="b">Show</button>
8
9 <script>
10 function showRoll() {
11 document.getElementById("out").innerHTML = "1602-24-733-001";
12 }
13
14 document.getElementById("b").onclick = showRoll;
15 </script>
16</body>
17</html>
untitled×
127.0.0.1:5500/index.html
live
Same three moves as the canteen page. Find the button, say what happens on click, change the paragraph. Once you can write these eight lines from memory, most of Module 11 is already yours.
2A classmate’s console shows Uncaught TypeError: Cannot set properties of null. Without seeing their code, what are the two most likely causes?
Show the solution
One — the id does not match. A typo in getElementById("..."), or the element has a different id, or a class where they meant an id. Nothing was found, so they got null.

Two — the script runs before the element exists. The script is in the <head> or above the element. The id is spelt perfectly; it has not been built yet.

How to tell in five seconds: move the script to the bottom of the body. Still broken means it is the spelling. Fixed means it was the placement.
3Why does console.log("hello") show nothing on the page, and when would you still want it?
Show the solution
Because it writes to the developer console, not the document. A visitor never sees it — it is not part of the page.

You want it constantly while writing code. To check a value is what you think it is, to confirm a function actually ran, to see what came back from a form field. It is the cheapest debugging tool there is: one line, no setup.

The rule: innerHTML for the user, console.log for you.
You have now written JavaScript that changes a page in response to a person. Everything from here is more of the same idea, done more carefully. Next: how to hold on to a value so you can use it later.
Module 3 · Variables, Data Types, let vs const · 38 min
CHUNK 1 OF 5 0:00 – 0:07

Holding on to a value

Covering the syllabus phrase: Variables
Module 2 printed things. Every value was written out in full, in the same breath as the printing. That works for one line and falls apart at two — which is what a variable fixes.
So far every piece of text has been typed straight into the code. That works once. The moment you want to use the same value twice, or change it, or read it from a form, you need somewhere to keep it.
New folder 03-variables inside FSWD-Unit2 · new files box.html · types.html · leak.html · join.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
A variable
A labelled box that holds one value. You put something in, you can look at it later, and — depending on how you made the box — you may be able to swap what is inside.
03-variables / box.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>A labelled box</title></head>
5<body>
6 <p id="out"></p>
7
8 <script>
9 let student = "Asha";
10
11 document.getElementById("out").innerHTML = student;
12
13 student = "Ravi";
14
15 document.getElementById("out").innerHTML += " then " + student;
16 </script>
17</body>
18</html>
untitled×
127.0.0.1:5500/index.html
live
one box, two different values, at two different moments
let student = "Asha"; makes the box, labels it student, and puts "Asha" in it. The word let is what makes a new box.
student on its own reads the box. Line 11 does not print the word “student” — it prints what is inside, which is Asha.
student = "Ravi"; replaces what is inside. No let this time — the box already exists, you are only changing its contents.
+= adds to what is already there rather than replacing it, which is why the paragraph ends up with both names.
The mistake to expect: writing let student = "Ravi"; on line 13. That tries to make a second box with the same label, and the browser refuses — SyntaxError: Identifier 'student' has already been declared. Use let once, when the box is born.
Naming a box needs let. Changing what is in it does not.
CHUNK 2 OF 5 0:07 – 0:15

What can go in the box

A box will hold anything, and JavaScript never asks you what kind. But it does keep track — and typeof will tell you what it thinks it is holding.
03-variables / types.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>What am I holding?</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 let name = "Asha";
10 let marks = 74;
11 let passed = true;
12 let grades = [74, 81, 66];
13 let student = { roll: 733, city: "Hyderabad" };
14 let absent;
15
16 let out = "";
17 out += typeof name + " <-- name" + "\n";
18 out += typeof marks + " <-- marks" + "\n";
19 out += typeof passed + " <-- passed" + "\n";
20 out += typeof grades + " <-- grades" + "\n";
21 out += typeof student + " <-- student" + "\n";
22 out += typeof absent + " <-- absent";
23
24 document.getElementById("out").innerHTML = out;
25 </script>
26</body>
27</html>
untitled×
127.0.0.1:5500/index.html
live
typeof reports what is actually in each box
Type
Holds
Written as
string
text of any length
"Asha" or 'Asha'
number
whole or decimal, no separate int
74   8.5   -3
boolean
true or false, nothing else
true   false
undefined
a box made but never filled
let absent;
null
emptied on purpose — typeof says "object", a 1995 bug (Module 13)
let winner = null;
symbol
a label guaranteed to be unique — rare in this unit
Symbol("id")
bigint
whole numbers too large for number
9007199254740993n
object
a group of named values
{ roll: 733 }
In our code
grades is a list
typeof says object — see the note below
PYQ · 15252 (S) N · Q3 · 2 marks
“Name four data types in JavaScript.”
String, Number, Boolean, Object. Add Undefined and Null if you want to be generous. Give a one-word example beside each — that is what turns a listed answer into a full-mark one.
Look at what grades reported. It is a list, but typeof said object. That is not a mistake in your code — JavaScript genuinely treats a list as a kind of object. It surprises everybody, and it is one of the quirks Module 13 traces back to 1995.
Coming from Java, notice what is missing. No int, no double, no char, no float. JavaScript has one number type for everything, and you never write the type when you make a box. The box works out what it is holding by itself.
CHUNK 3 OF 5 0:15 – 0:25

let, const, and the old word you should not use

Covering the syllabus phrase: Introduction to JavaScript ES6 — this is the change ES6 is best known for.
letMake a box whose contents can change. A score that goes up, a message that gets replaced, a name read from a form.
constMake a box whose contents cannot be swapped. A tax rate, a maximum, an element you found once and will keep using.
PYQ · 15252 (S) N · Q12(a) · 4 marks
“Describe the use of ‘let’ and ‘const’ in JavaScript ES6.”
Four things, one mark each. 1. Both were introduced in ES6 (2015) to replace var. 2. Both are block scoped — they exist only inside the { } they were made in. 3. let can be reassigned; const cannot. 4. const must be given a value immediately. Add one line of code for each and the four marks are safe.

Now the old word, and why it is a trap

Before ES6 there was only var. It still works, you will see it in old code and in your question papers — and it behaves in a way that catches people out.
03-variables / leak.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>var leaks</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 let out = "";
10
11 if (true) {
12 var leaked = "I escaped the block";
13 let stayed = "I did not";
14 }
15
16 out += leaked + "\n";
17 out += typeof stayed + " <-- stayed is not reachable here";
18
19 document.getElementById("out").innerHTML = out;
20 </script>
21</body>
22</html>
untitled×
127.0.0.1:5500/index.html
live
one of these two escaped the block it was made in
if (true) { var leaked let stayed } THE BLOCK var walks straight out let stays where it was made A box you can still reach from outside the room you made it in is a box you can change by accident.
The one difference that matters · and the reason ES6 added let
Use const by default. Use let when it has to change.
Do not use var at all.
CHUNK 4 OF 5 0:25 – 0:32

Joining text without losing your mind

Almost every message you show a user is part fixed text and part variable. There are two ways to stitch them together, and ES6 added the second one because the first is so often got wrong.
03-variables / join.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Joining text</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const name = "Asha";
10 const roll = "1602-24-733-001";
11 const marks = 74;
12
13 const oldWay = "Hi " + name + ", roll " + roll + ", you scored " + marks;
14
15 const newWay = `Hi ${name}, roll ${roll}, you scored ${marks}`;
16
17 document.getElementById("out").innerHTML = oldWay + "\n" + newWay;
18 </script>
19</body>
20</html>
untitled×
127.0.0.1:5500/index.html
live
same sentence, both ways — identical output
The old way — +Count the quotes. Count the spaces. Miss one + and it breaks; miss a space and words run together. Works everywhere, but it is fiddly.
The ES6 way — backticksWrite the sentence normally and drop values in with ${ }. A space stays a space. This is what you should use.
The quote is a backtick `, not an apostrophe. On most keyboards it is the key left of 1, sharing with ~.
Inside backticks, ${...} means “put the value here”. Anything can go inside the braces — a variable, a sum, a function call.
Everything else is literal text, including spaces and line breaks. That is the whole appeal: what you type is what you get.
You will still see + in the papers, because the questions predate ES6 in places. Both are correct and both earn full marks. Read + fluently; write backticks.
CHUNK 5 OF 5 0:32 – 0:38

Checkpoint and practice

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-practice · 02-first-script └── 03-variables ├── box.html new ├── types.html new ├── leak.html new └── join.html new
1Three const values — a price of 60, a quantity of 3, and the total. Show the sentence 3 dosas at ₹60 each = ₹180 using backticks.
Show the solution
03-variables / total.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Order total</title></head>
5<body>
6 <p id="out"></p>
7
the working out8 <script>
9 const price = 60;
10 const qty = 3;
11 const total = price * qty;
12
13 document.getElementById("out").innerHTML =
14 `${qty} dosas at ₹${price} each = ₹${total}`;
15 </script>
16</body>
17</html>
untitled×
127.0.0.1:5500/index.html
live
Notice total is a const too. It is worked out once and never changed, so it does not need let. That is the habit: reach for const first and only downgrade when you find you must.
2What does this print, and why?
const marks = [74, 81];
marks.push(66);
console.log(marks.length);
Is that not supposed to be impossible with const?
Show the solution
It prints 3, and it is perfectly legal.

const does not mean the value cannot change — it means the box cannot be pointed at something else. The list is still the same list; you have added to it. What const forbids is marks = [1, 2], which would try to put a different list in the box.

The wording that earns the mark: const prevents reassignment, not modification.
3Name four JavaScript data types with an example of each, then say what typeof reports for a list — and why that is surprising.
Show the solution
String "Asha" · Number 74 · Boolean true · Object { roll: 733 }. Undefined and Null are the other two worth mentioning.

typeof [74, 81] reports "object". Surprising because a list feels like its own kind of thing — but in JavaScript a list is a kind of object, with numbered keys instead of named ones.

If you need to be sure something is a list, Array.isArray(grades) answers properly. Module 6 uses it.
You can now hold a value, change it, check what it is, and build a sentence out of it. Next: wrapping a set of instructions up so you can run them whenever you like.
Module 4 · Functions and Arrow Functions · 38 min
CHUNK 1 OF 4 0:00 – 0:09

Instructions you can run again

Covering the syllabus phrase: Scripting Functions
Module 3 gave you a box for a value. This gives you a box for a set of instructions — something you can put away and run again, rather than retyping.
You have written the same three lines to find an element and change it, several times now. A function lets you write instructions once, give them a name, and run them whenever you like — with different values each time.
New folder 04-functions inside FSWD-Unit2 · new files greet.html · four.html · arrows.html · this.html · fare.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
A function
A recipe. Written down once, followed as many times as you want. It can take ingredients in (parameters) and hand a result back (return).
04-functions / greet.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>A recipe</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 function greet(name) {
10 return "Welcome, " + name;
11 }
12
13 let out = "";
14 out += greet("Asha") + "\n";
15 out += greet("Ravi") + "\n";
16 out += greet("Meera");
17
18 document.getElementById("out").innerHTML = out;
19 </script>
20</body>
21</html>
untitled×
127.0.0.1:5500/index.html
live
one recipe, cooked three times, three different results
function greet(name) { writes the recipe down and names it greet. Nothing runs yet — a written recipe is not a meal.
name is the ingredient slot. Whatever you hand in when you call it lands in name for the length of that one run.
return hands a value back to whoever called it. Line 14 does not print anything itself — it returns a piece of text, and the caller decides what to do with it.
greet("Asha") cooks it. This is the moment the instructions actually run. Three calls, three separate runs, no interference between them.
greet(name) return "Welcome, " + name WRITTEN ONCE greet("Asha") greet("Ravi") greet("Meera") CALLED THREE TIMES Welcome, Asha Welcome, Ravi Welcome, Meera THREE RESULTS
One set of instructions · three separate runs, none of them aware of the others
From Java, two things are missing. There is no return type in front of the name — no String greet(...), only function greet(...). And there is no class to put it in. A function can sit on its own in a file, which in Java it never could.
CHUNK 2 OF 4 0:09 – 0:18

The same function, four ways

JavaScript lets you write a function in several shapes. They all do the same job here. You need to recognise all four, because the papers use them interchangeably — and you need to write the last one, because that is what everyone writes now.
04-functions / four.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Three ways</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 function areaA(side) {
10 return side * side;
11 }
12
13 const areaB = function (side) {
14 return side * side;
15 };
16
17 const areaC = (side) => {
18 return side * side;
19 };
20
21 const areaD = side => side * side;
22
23 let out = "";
24 out += areaA(4) + " <-- declaration\n";
25 out += areaB(4) + " <-- expression\n";
26 out += areaC(4) + " <-- arrow\n";
27 out += areaD(4) + " <-- arrow, short";
28
29 document.getElementById("out").innerHTML = out;
30 </script>
31</body>
32</html>
untitled×
127.0.0.1:5500/index.html
live
four spellings, one answer — 16 every time
Line 9 — declaration. The word function comes first, then the name. This shape is hoisted, which means you can call it on a line above where it is written. The other three cannot do that.
Line 13 — expression. A nameless function put into a box. Now areaB holds a function the same way a box could hold a number.
Line 17 — arrow. Same as the expression, with function deleted and => added after the brackets. That is the entire change.
Line 21 — arrow, shortened twice. One parameter so the brackets go; one expression so the braces and return go. What is left is almost the maths itself.
Shape
Written as
When you see it
Declaration
function area(s) { }
older code, and every textbook
Expression
const area = function (s) { }
a function stored in a box
Arrow
const area = (s) => { }
ES6 onward — the modern default
Arrow, short
const area = s => s * s
one parameter, one expression
In our code
lines 9, 13, 17 and 21
all four return 16
One place the four shapes are not interchangeable. A declaration can be called on a line above where it is written — the browser reads the whole file first and files the declarations away. The other three cannot. Move line 21 to the top of the script and you get ReferenceError: Cannot access 'areaD' before initialization. Write your functions before you call them and this never comes up.
Note the semicolon on line 15 and 19, but not on line 12. An expression and an arrow are assignments — you are putting something in a box, so the statement ends with ;. A declaration is not an assignment, so it does not. Nothing breaks if you get it wrong, but it is the kind of detail a marker notices.
CHUNK 3 OF 4 0:18 – 0:30

Arrow functions, in full

Covering Introduction to JavaScript ES6 — arrow functions are the other headline ES6 change, and they are asked in two of your four papers.
The arrow is not a different kind of function. It is a shorter way to write the same thing, and once you know the four shortenings you can read any of them.
One parameter needs no brackets. name => ... is the same as (name) => .... Both are correct; the short one is more common.
No parameters needs empty brackets. () => "OI!". You cannot leave them out entirely.
One expression needs no braces and no return. s => s * s returns automatically. Add braces and you must write return yourself.
A default value goes in the bracket. (amount, rate = 0.05) — leave rate out when calling and it uses 0.05.
...marks collects however many arrive. Call it with four numbers or forty; they arrive as a list called marks.
04-functions / arrows.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Arrow shapes</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const greet = name => `Hello, ${name}!`;
10
11 const add = (a, b) => a + b;
12
13 const shout = () => "OI!";
14
15 const fee = (amount, rate = 0.05) => amount * rate;
16
17 const total = (...marks) => marks.reduce((a, b) => a + b, 0);
18
19 let out = "";
20 out += greet("Asha") + "\n";
21 out += add(7, 5) + "\n";
22 out += shout() + "\n";
23 out += fee(2000) + "\n";
24 out += total(74, 81, 66, 90);
25
26 document.getElementById("out").innerHTML = out;
27 </script>
28</body>
29</html>
untitled×
127.0.0.1:5500/index.html
live
five arrow functions, every shape you will meet
PYQ · 15259 N · Q5 · 2 marks
“Write an arrow function to greet the user.”
const greet = name => `Hello, ${name}!`;
console.log(greet("Asha"));  // Hello, Asha!
Two marks, two things: the arrow itself, and a call showing it works. One line each. Writing only the function and not calling it is where the second mark usually goes missing.
PYQ · 15267 N/O · Q5 · 2 marks
“Write an arrow function to perform sum of numbers contained in an array.”
const total = marks => marks.reduce((a, b) => a + b, 0);
console.log(total([74, 81, 66]));  // 221
The 0 at the end matters — it is the starting total, and without it an empty list throws an error. reduce is covered properly in Module 6; a plain for loop earns the same marks if you prefer it.

The one thing an arrow does differently

A group of values can carry its own functions. Ask each shape for the name and they disagree.
04-functions / this.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Who is this?</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const student = {
10 firstName: "Asha",
11 greet() { return this.firstName; },
12 greetArrow: () => this.firstName
13 };
14
15 let out = "";
16 out += student.greet() + " <-- normal method\n";
17 out += student.greetArrow() + " <-- arrow function";
18
19 document.getElementById("out").innerHTML = out;
20 </script>
21</body>
22</html>
untitled×
127.0.0.1:5500/index.html
live
the same object, asked two ways
greet() is a normal method. Inside it, this is whatever sits before the dot — student — so it hands back Asha.
greetArrow prints undefined, with no error. An arrow function does not get its own this, so use a normal method when you need the object.
Arrow functions are not a new idea.
They are the same function, written with less ceremony.
CHUNK 4 OF 4 0:30 – 0:38

Putting it on a page

A function on its own is theory. Here it is doing a job on a real page — and notice the arrow appearing twice, once as your calculation and once as the thing the button runs.
04-functions / fare.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Bus fare</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 input { padding: 8px; width: 120px; }
9 button { padding: 8px 16px; background: skyblue; }
10 </style>
11</head>
12<body>
13 <h3>Bus fare</h3>
14
15 <label>Kilometres</label>
16 <input id="km" value="12">
17
18 <button id="go">Work it out</button>
19 <p id="out"></p>
20
21 <script>
22 const fare = km => 10 + km * 2.5;
23
24 document.getElementById("go").onclick = () => {
25 const km = Number(document.getElementById("km").value);
26 document.getElementById("out").innerHTML = `Fare: \u20B9${fare(km)}`;
27 };
28 </script>
29</body>
30</html>
untitled×
127.0.0.1:5500/index.html
live
change the kilometres and press the button
fare knows one thing — how to turn kilometres into rupees. It does not know about buttons, pages or text boxes, and that is why it is quick to test and ready to reuse.
Number(...) matters. A text box always hands back text, even when it looks like a number. Without it, "12" * 2.5 happens to work, but "12" + 2.5 would give you "122.5". Module 13 explains why.
The click handler is itself an arrow function. () => { ... } — no parameters, several statements, so braces are needed. This is the shape you will write hundreds of times.

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-practice · 02-first-script · 03-variables └── 04-functions ├── greet.html new ├── four.html new ├── arrows.html new ├── this.html new └── fare.html new

Practice

1Write an arrow function isEven that takes a number and returns true or false. Use the shortest form that works.
Show the solution
04-functions / even.htmlruns
1<script>
2 const isEven = n => n % 2 === 0;
3
4 console.log(isEven(4));
5 console.log(isEven(7));
6</script>
untitled×
127.0.0.1:5500/index.html
live
One parameter, one expression — so no brackets round n, no braces, no return. n % 2 gives the remainder; === 0 turns that into true or false. Three equals signs, not two — Module 13 explains why that matters more than it looks.
2What is wrong with this, and what does it return?
const square = n => { n * n };
console.log(square(5));
Show the solution
It returns undefined.

The braces turn it into a full function body, and a full body must say return. n * n is calculated and thrown away. No error is raised, which is what makes this one nasty — it silently gives you nothing.

Two fixes: drop the braces — n => n * n — or keep them and write return n * n;.

The rule: no braces means automatic return; braces mean you say it yourself.
3A function should charge 5% by default but allow a different rate. Write it as an arrow function and show both ways of calling it.
Show the solution
const fee = (amount, rate = 0.05) => amount * rate;

console.log(fee(2000));       // 100 — uses the default
console.log(fee(2000, 0.12)); // 240 — overrides it
The default only applies when the argument is left out or passed as undefined. Pass 0 and you get 0, not the default — which is usually what you want, and occasionally a surprise.
You can now wrap up instructions and run them on demand. Next: grouping related values together, so a student is one thing rather than four loose variables.
Module 5 · Objects · 35 min
CHUNK 1 OF 4 0:00 – 0:08

Keeping related things together

Covering the syllabus phrase: Objects
Module 3 gave you boxes. Here is the problem with boxes: a student has a name, a roll number, a city and marks, and four separate boxes have no idea they describe the same person.
New folder 05-objects inside FSWD-Unit2 · new files student.html · edit.html · record.html · average.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
05-objects / loose.html  — four boxes, no connectionfragment
1<script>
2 let name = "Asha";
3 let roll = "1602-24-733-001";
4 let city = "Hyderabad";
5 let marks = 74;
6
7 // four separate boxes. Nothing says they belong together.
8</script>
untitled×
127.0.0.1:5500/index.html
live
Nothing links them. Add a second student and you need name2, roll2, city2, marks2. Then a third.
You cannot hand one student to a function. You would have to pass four arguments and hope they stay in the right order.
You cannot store a list of them. Which is exactly what a class register is.
An object
A labelled drawer. One thing, with named compartments inside it. The drawer has a name; each compartment has a label and a value.
05-objects / student.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Student record</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const student = {
10 name: "Asha",
11 roll: "1602-24-733-001",
12 city: "Hyderabad",
13 marks: 74
14 };
15
16 let out = "";
17 out += student.name + "\n";
18 out += student.roll + "\n";
19 out += student["city"] + " <-- same thing, other spelling\n";
20 out += student.marks;
21
22 document.getElementById("out").innerHTML = out;
23 </script>
24</body>
25</html>
untitled×
127.0.0.1:5500/index.html
live
one drawer, four labelled compartments
Curly braces make the drawer. { } for an object, [ ] for an array. Two different brackets, two different shapes of container.
Each line inside is label: value. A colon between them, a comma at the end — except the last, where the comma is optional.
student.name reaches into the drawer. The drawer name, a dot, then the compartment label. Read it as “the name of the student”.
Lines 18 and 20 do the same thing, spelled differently. Both fetch the city. The next section explains when you would ever want the longer one.
FOUR LOOSE BOXES name "Asha" roll "1602-..." city "Hyderabad" marks 74 no connection between them group ONE DRAWER student name: "Asha" roll: "1602-24-733-001" city: "Hyderabad" marks: 74 one name for the whole person pass it, store it, copy it, list it
The same four facts · loose, then gathered under one name
student.cityDot notation. Shorter, easier to read, and what you will write almost always.
student["city"]Bracket notation. Needed when the label is held in a variable or has a space in it. Module 11 uses this.
CHUNK 2 OF 4 0:08 – 0:17

Adding, changing, removing

A drawer is not sealed. You can add a compartment after it was built, change what is in one, or take one out entirely — and JavaScript lets you do all three with the same simple syntax.
05-objects / edit.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Editing a record</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const user = { name: "Karan", age: 21 };
10
11 user.city = "Hyderabad";
12
13 user.age = 22;
14
15 delete user.name;
16
17 let out = "";
18 out += JSON.stringify(user) + "\n\n";
19 out += "has city? " + ("city" in user) + "\n";
20 out += "has name? " + ("name" in user) + "\n";
21 out += "labels: " + Object.keys(user);
22
23 document.getElementById("out").innerHTML = out;
24 </script>
25</body>
26</html>
untitled×
127.0.0.1:5500/index.html
live
one object, three edits, then a look inside
user.city = "Hyderabad"; adds a compartment. It did not exist a line earlier. No declaration, no announcement — assign to a label that is not there and it appears.
user.age = 22; changes one. Identical syntax. JavaScript works out which you meant by whether the label already exists.
delete user.name; removes one. The compartment is gone, not emptied — asking for user.name now gives undefined.
Two helpers used on line 18 and 19. JSON.stringify(user) turns the whole drawer into readable text so you can see it in one go — handy for checking your work. "city" in user asks whether a label exists and answers true or false.
Object.keys(user) lists the labels. Useful when you want to walk through an object without knowing in advance what is in it.
PYQ · 15279 N/O · Q4 · 2 marks
“let user = {name: “Karan”, age: 21}; — write JavaScript code to add a new property city: “Hyderabad”.”
user.city = "Hyderabad";
// or, when the label is in a variable:
user["city"] = "Hyderabad";
One line is the answer. For the second mark, add console.log(user); to show the result, and mention that assigning to a label that does not exist creates it. Examiners are looking for that sentence.
Look at line 9 — it says const, and we changed the object anyway. This is the point Module 3 made: const stops you pointing the box at a different object. It does not freeze what is inside. user = { } would fail; user.age = 22 is fine.
CHUNK 3 OF 4 0:17 – 0:28

Drawers can hold lists, and they can do things

A compartment does not have to hold a single value. It can hold a list, and it can hold a function — which turns a passive record into something that can answer questions about itself.
05-objects / record.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>A fuller record</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const name = "Asha";
10 const city = "Hyderabad";
11
12 const student = {
13 name,
14 city,
15 grades: [74, 81, 66],
16
17 average() {
18 const total = student.grades.reduce((a, b) => a + b, 0);
19 return (total / student.grades.length).toFixed(1);
20 }
21 };
22
23 const { name: who, city: where } = student;
24
25 let out = "";
26 out += `${who} from ${where}\n`;
27 out += "grades: " + student.grades + "\n";
28 out += "second: " + student.grades[1] + "\n";
29 out += "average: " + student.average();
30
31 document.getElementById("out").innerHTML = out;
32 </script>
33</body>
34</html>
untitled×
127.0.0.1:5500/index.html
live
a record that can work out its own average
Shorthand. Lines 13 and 14 say only name, and city,. When the label and the variable have the same name, write it once. It means exactly name: name.
A list in a compartment. grades: [74, 81, 66]. Reach into it with student.grades[1] — the drawer, then the shelf, then the position. Counting starts at 0, so that gives 81.
A function in a compartment is called a method. average() belongs to this student and is called with student.average().
this means “the drawer I am in”. Inside average, this.grades is that student’s grades. Without this the method would not know whose marks to add up.
Unpacking. Line 23 pulls two compartments out into their own variables in one line, renaming them on the way. Handy when a function receives a big object and only needs two things from it.
One rule about this worth knowing now: write average() as a normal method, not as an arrow function. An arrow does not get its own this, so this.grades inside an arrow would not find the student. It is the one place in this unit where the old shape is the right one.
A drawer that can answer questions about itself
is the whole idea behind objects.
CHUNK 4 OF 4 0:28 – 0:35

The exam question, in full

PYQ · 15267 N/O · Q12(b) · 4 marks
“Write a JavaScript program to create an object representing a student with properties like name, age, and grades (an array). Write a function to calculate the average grade on a button click by accepting the data from a form.”
Everything this module covered, in one page: an object, a list inside it, a function that takes the object, and a button that builds the object from what the user typed. Type in the frame and press the button — it works.
05-objects / average.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Average grade</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 label { display: block; margin-bottom: 12px; }
9 input { padding: 8px; width: 200px; }
10 button { padding: 8px 16px; background: skyblue; }
11 </style>
12</head>
13<body>
14 <h3>Student average</h3>
15
16 <label>Name</label>
17 <input id="nm" value="Asha">
18
19 <label>Age</label>
20 <input id="ag" value="20">
21
22 <label>Grades, comma separated</label>
23 <input id="gr" value="74, 81, 66">
24
25 <button id="go">Work out the average</button>
26 <p id="out"></p>
27
28 <script>
29 const average = s =>
30 s.grades.reduce((a, b) => a + b, 0) / s.grades.length;
31
32 document.getElementById("go").onclick = () => {
33 const student = {
34 name: document.getElementById("nm").value,
35 age: Number(document.getElementById("ag").value),
36 grades: document.getElementById("gr").value
37 .split(",").map(Number)
38 };
39
40 document.getElementById("out").innerHTML =
41 `${student.name}, age ${student.age}, average ${average(student).toFixed(1)}`;
42 };
43 </script>
44</body>
45</html>
untitled×
127.0.0.1:5500/index.html
live
change any field and press the button
The object is built when the button is clicked, not before. It has to be — the values do not exist until somebody types them.
.split(",") turns "74, 81, 66" into three pieces of text — it cuts a string wherever it finds the character you name. Module 7 covers it properly; for now, take it as the tool that turns one string into a list.
.map(Number) turns each piece into a real number. It runs Number over every item and hands back a new list. Module 6 covers it properly. Without it you would be adding text together and getting "748166" rather than 221.
average takes the whole student rather than a loose list. That is the habit the question is testing: pass one thing, not three.
.toFixed(1) rounds a number to one decimal place, so you get 73.7 rather than 73.66666666666667.
Line
What it does
Leave it out and…
27–28
the average function, taking a whole student
you would pass three loose values instead
31–36
builds the object from what was typed
the object would hold the starting values forever
Number(...)
turns the age text into a real number
age would be text, and any sum on it would go wrong
.split(",")
cuts "74, 81, 66" into three pieces
you would have one long string, not three marks
.map(Number)
turns each piece into a number
adding them would glue text: "748166"
In our page
press the button with 74, 81, 66
you get 73.7

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-practice · 02-first-script · 03-variables · 04-functions └── 05-objects ├── student.html new ├── edit.html new ├── record.html new └── average.html new

Practice

1A library book object with title, author and copies. Add a method issue() that reduces the copies by one and reports how many are left — refusing when there are none.
Show the solution
05-objects / book.htmlruns
1<script>
2 const book = {
3 title: "Let Us C",
4 author: "Kanetkar",
5 copies: 3,
6
7 issue() {
8 if (book.copies === 0) return "none left";
9 book.copies = book.copies - 1;
10 return `issued, ${book.copies} left`;
11 }
12 };
13
14 console.log(book.issue());
15 console.log(book.issue());
16</script>
untitled×
127.0.0.1:5500/index.html
live
The early return is the important bit. Check the impossible case first and leave; then the rest of the method can assume things are fine. It reads better than wrapping everything in an else, and it is a habit worth building now.
2What does this print, and why is it not what most people expect?
const a = { marks: 74 };
const b = a;
b.marks = 90;
console.log(a.marks);
Show the solution
It prints 90.

const b = a did not make a second drawer. It made a second label on the same drawer. Change it through b and a shows the change, because there was only ever one object.

To get a real copy: const b = { ...a }; — the three dots spread the contents into a new drawer.

The wording for a marker: objects are assigned by reference, not by value. Numbers and text are copied; objects are shared.
3student.average and student.average() — what is the difference, and what does each give you?
Show the solution
Without brackets you get the recipe. With brackets you get the meal.

student.average hands back the function itself — printing it shows the source code. student.average() runs it and hands back the answer.

This is a real bug people hit, usually written as innerHTML = student.average, which puts the function's source text on the page. If your page shows something starting with function or containing =>, you forgot the brackets.
You can now hold a whole record in one place and let it answer questions about itself. Next: what happens when you need a hundred of them — ordered, countable, and searchable.
Module 6 · Arrays and Array Methods · 42 min
CHUNK 1 OF 5 0:00 – 0:08

Many things, in order

Covering the syllabus phrase: Arrays
An object groups different facts about one thing. An array holds many of the same kind of thing, in a fixed order, and lets you get at any of them by position.
New folder 06-arrays inside FSWD-Unit2 · new files shelf.html · change.html · sort.html · typo.html · walk.html · filter.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
An array
A numbered shelf. Items sit in a row, each with a position. You can read one by its number, count them, add more at either end, or take some out.
const cars = [ "Swift", "Nexon", "Creta", "Thar" ]; Swift Nexon Creta Thar 0 1 2 3 counting starts here 4 length last is length − 1
Four items · positions 0 to 3 · length 4
06-arrays / shelf.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>A numbered shelf</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const cars = ["Swift", "Nexon", "Creta", "Thar"];
10
11 let out = "";
12 out += "first: " + cars[0] + "\n";
13 out += "second: " + cars[1] + "\n";
14 out += "last: " + cars[cars.length - 1] + "\n";
15 out += "how many:" + cars.length + "\n";
16 out += "beyond: " + cars[9];
17
18 document.getElementById("out").innerHTML = out;
19 </script>
20</body>
21</html>
untitled×
127.0.0.1:5500/index.html
live
look at the last line — there is no position 9
Square brackets make the shelf. ["Swift", "Nexon"] — items separated by commas.
Counting starts at 0, not 1. cars[0] is Swift. This trips up everybody at first, and it is the same in Java, so you have met it before.
.length counts the items — 4 here. So the last one is always at length - 1, which is 3.
Ask for a position that is not there and you get undefined, not an error. JavaScript shrugs. In Java that same line would throw ArrayIndexOutOfBoundsException and stop the program.
PYQ · 15252 (S) N · Q4 · 2 marks
“Write JavaScript code to create an array to store list of different types of cars.”
const cars = ["Swift", "Nexon", "Creta", "Thar"];
console.log(cars.length);  // 4
One line answers it. For the second mark show you can reach into it — print cars[0] or the length. A bare declaration with nothing done to it often gets one mark.
CHUNK 2 OF 5 0:08 – 0:16

Adding and removing along the shelf

Five method names cover almost everything you will do to a list. Two add, two remove, and one does whatever you ask. The names are odd but they come in pairs, which makes them easier to hold on to.
At the endpush(x) adds · pop() removes and hands the item back. Fast, and what you will use most.
At the startunshift(x) adds · shift() removes. Everything after it has to shuffle along, so use these only when order demands it.
06-arrays / change.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Changing the shelf</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const q = ["Asha", "Ravi"];
10 let out = "start: " + q + "\n";
11
12 q.push("Meera");
13 out += "push: " + q + "\n";
14
15 q.unshift("Iqbal");
16 out += "unshift: " + q + "\n";
17
18 const last = q.pop();
19 out += "pop: " + q + " took " + last + "\n";
20
21 const first = q.shift();
22 out += "shift: " + q + " took " + first + "\n";
23
24 q.splice(1, 0, "Kavya");
25 out += "splice: " + q;
26
27 document.getElementById("out").innerHTML = out;
28 </script>
29</body>
30</html>
untitled×
127.0.0.1:5500/index.html
live
six operations, each printing the shelf afterwards
push and unshift add. Push at the back of the queue, unshift at the front.
pop and shift remove and hand the item back. That is why line 16 can catch it in last. If you do not want it, ignore the return.
splice(1, 0, "Kavya") reads as: at position 1, remove 0 items, insert Kavya. Change the middle number to remove instead. It is the one that does everything, and the one people look up every time.
All five change the original list. They do not hand you a new one. Note the array is const and this all still works — same rule as objects: const stops reassignment, not modification.
CHUNK 3 OF 5 0:16 – 0:25

sort, and the trap everybody falls into

This one has been an exam question, and it catches people because the wrong answer looks almost right. Sort these four numbers and see.
06-arrays / sort.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>The sort trap</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const nums = [5, 10, 2, 8];
10
11 const wrong = [...nums].sort();
12
13 const up = [...nums].sort((a, b) => a - b);
14
15 const down = [...nums].sort((a, b) => b - a);
16
17 let out = "";
18 out += "original: " + nums + "\n";
19 out += "plain sort: " + wrong + " <-- wrong!\n";
20 out += "ascending: " + up + "\n";
21 out += "descending: " + down;
22
23 document.getElementById("out").innerHTML = out;
24 </script>
25</body>
26</html>
untitled×
127.0.0.1:5500/index.html
live
look at "plain sort" — 10 came before 2
sort() on its own treats everything as text. It compares "10" and "2" the way a dictionary would — character by character. "1" comes before "2", so 10 lands before 2. It is not broken; it is doing exactly what it was told, which is the least helpful kind of wrong.
Give sort a rule and it obeys you. (a, b) => a - b means: hand me two, and I will tell you which goes first.
Negative means a first, positive means b first. So a - b puts small numbers first — ascending. Swap it to b - a and you get descending.
[...nums] makes a copy first. Without it, sort would rearrange the original — and the three examples would interfere with each other. Same three dots you met in Module 5.
WHAT sort ASKS, OVER AND OVER (a, b) => a - b given any two, which goes first? negative → a first positive → b first zero → leave them 5 − 10 = −5 so 5 goes first 10 − 2 = 8 so 2 goes first swap to b − a and every answer flips
The comparator is a question, asked about every pair, until the shelf is in order
PYQ · 15279 N/O · Q3 · 2 marks
“Write a JavaScript program to sort the given array let nums = [5, 10, 2, 8]; in descending order.”
let nums = [5, 10, 2, 8];
nums.sort((a, b) => b - a);
console.log(nums);  // [10, 8, 5, 2]
The comparator is the whole question. Writing nums.sort().reverse() looks clever and gives [8, 5, 2, 10] — wrong, for the reason above. Say in one line why the comparator is needed and the second mark is safe.

When the method name is misspelt

06-arrays / typo.html  — one letter wrongruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>One letter wrong</title></head>
5<body>
6 <p id="err" style="color: red;"></p>
7 <script>
8 window.addEventListener("error", e => {
9 document.getElementById("err").innerHTML = e.message;
10 });
11 </script>
12 <script>
13 const nums = [5, 10, 2, 8];
14 nums.srot((a, b) => a - b);
15 </script>
16</body>
17</html>
untitled×
127.0.0.1:5500/index.html
live
the red line is the console’s own message
A typo in a method name stops the script on that line. The array has no method called srot, so there is nothing to call — correct it to sort and the red line goes away. Lines 8 to 12 only copy the console’s message onto the page so you can read it here.
A bare sort() sorts like a dictionary, not like a calculator.
CHUNK 4 OF 5 0:25 – 0:36

forEach and map, side by side

These two look almost identical and are asked about directly in the papers. They do the same walk along the shelf. The difference is entirely in what you get back at the end.
06-arrays / walk.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>forEach and map</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const marks = [74, 81, 66];
10 let out = "";
11
12 const fe = marks.forEach(m => m + 5);
13
14 const mp = marks.map(m => m + 5);
15
16 out += "original: " + marks + "\n";
17 out += "forEach: " + fe + " <-- hands back nothing\n";
18 out += "map: " + mp + " <-- hands back a new list\n\n";
19
20 marks.forEach(m => { out += "printed " + m + "\n"; });
21
22 document.getElementById("out").innerHTML = out;
23 </script>
24</body>
25</html>
untitled×
127.0.0.1:5500/index.html
live
same arrow function, two very different results
forEach · walks and does something 74 81 66 m => m + 5 undefined the answers are thrown away map · walks and collects 74 81 66 m => m + 5 79 86 71 a brand new list, original untouched
Identical walk · the difference is only what comes out of the end
forEach
map
Hands back
undefined — nothing
a new array, same length
Original list
untouched
untouched
Reach for it when
you want to do something — print, add to a page
you want to make something — a transformed list
Can you chain it?
No — there is nothing to chain onto
Yes — .map().filter().join()
In our code
line 20 builds up the printed text
line 14 makes [79, 86, 71]
CHUNK 5 OF 5 0:36 – 0:42

filter, find, reduce — and the exam question

Three more, each answering a different question about a list. Then all of them together, because the paper asks for exactly that combination.
filter
Keeps the items that pass a test. Hands back a shorter list. marks.filter(m => m >= 50)
find
Hands back the first item that passes, not a list. marks.find(m => m >= 80)
reduce
Boils the whole list down to one value — usually a total. marks.reduce((a, b) => a + b, 0)
PYQ · 15279 N/O · Q12(b) · 4 marks
“What is the difference between map() and forEach() in arrays? Given an array of objects containing name and price, write JavaScript code to find all the objects that have price greater than 100, sort them and display.”
Two halves. The difference is the table above — forEach returns undefined and is used for side effects; map returns a new array of the same length. Then the program: filter, sort, display.
06-arrays / filter.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Price filter</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 button { padding: 8px 16px; background: skyblue; }
9 </style>
10</head>
11<body>
12 <h3>Items over &#8377;100</h3>
13 <button id="go">Show them</button>
14 <ul id="out"></ul>
15
16 <script>
17 const items = [
18 { name: "Notebook", price: 60 },
19 { name: "Backpack", price: 900 },
20 { name: "Pen", price: 20 },
21 { name: "Calculator", price: 450 }
22 ];
23
24 document.getElementById("go").onclick = () => {
25 const costly = items
26 .filter(i => i.price > 100)
27 .sort((a, b) => a.price - b.price)
28 .map(i => `<li>${i.name} &mdash; &#8377;${i.price}</li>`)
29 .join("");
30
31 document.getElementById("out").innerHTML = costly;
32 };
33 </script>
34</body>
35</html>
untitled×
127.0.0.1:5500/index.html
live
press the button — two items are over ₹100
Four methods chained in one statement. filter narrows it to two items, sort orders them by price, map turns each into a line of HTML, join("") glues those lines into one string.
Chaining works because each one hands back an array. This is exactly why map is useful and forEach is not — you could not chain anything after a forEach.
join("") with empty quotes means no separator. Leave it out entirely and you get commas between your list items, which shows up on the page.

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-first-script · 03-variables · 04-functions · 05-objects └── 06-arrays ├── shelf.html new ├── change.html new ├── sort.html new ├── typo.html new ├── walk.html new └── filter.html new

Practice

1From [74, 81, 66, 90, 45]: the passes (50 and above), the highest, the first mark of 80 or more, and the average. One line each.
Show the solution
06-arrays / stats.htmlruns
1<script>
2 const marks = [74, 81, 66, 90, 45];
3
4 const passed = marks.filter(m => m >= 50);
5 const highest = Math.max(...marks);
6 const first80 = marks.find(m => m >= 80);
7 const total = marks.reduce((a, b) => a + b, 0);
8
9 console.log(passed, highest, first80, total / marks.length);
10</script>
untitled×
127.0.0.1:5500/index.html
live
Math.max(...marks) uses the three dots againMath.max wants separate numbers, not a list, and the dots spread the list into separate arguments. Math.max(marks) without them gives NaN.
2Why does this print [1, 10, 2, 20, 3], and what is the fix?
const n = [10, 2, 1, 20, 3];
console.log(n.sort());
Show the solution
Because a bare sort() compares them as text. It turns each number into a string and orders them the way a dictionary would — "1", then "10", then "2". Character by character, "1" beats "2", so 10 lands before 2.

The fix: n.sort((a, b) => a - b).

Why the default behaves this way: sort has to work on names and dates too, so text order is the only rule that fits everything. Another decision from 1995 you cannot change now.
3You want to put every car name on the page as a list item. Which of forEach and map would you choose, and why?
Show the solution
Either works. map is cleaner.

With map: cars.map(c => `<li>${c}</li>`).join("") builds the whole string in one expression and hands it to you.

With forEach you need a variable outside the loop to collect into: let html = ""; cars.forEach(c => html += ...);. Three lines instead of one, and an extra let to keep track of.

The rule: if you want a result back, use map. If you only want a side effect, use forEach.
You can now hold many things, order them, narrow them and total them. Next: doing the same kind of careful work on text — which is what every validation question in the paper actually is.
Module 7 · String Manipulation · 36 min
CHUNK 1 OF 4 0:00 – 0:08

Working with what the user typed

Covering the syllabus phrase: String Manipulation
Everything a person types into a form arrives as a string. Every validation question in your papers is really a string question underneath. So this module is quietly one of the most useful in the unit.
New folder 07-strings inside FSWD-Unit2 · new files row.html · methods.html · compare.html · names.html · shout.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
A string
A row of characters, numbered from 0, exactly like an array. You can read any position, count them, and cut pieces out — but you cannot change one in place.
const name = "Asha Reddy"; A s h a space R e d d y 012 345 6789 name[0] name[9] the space counts — length is 10, not 9 name[0] = "M"; silently does nothing
Ten characters, positions 0 to 9 · readable, countable, but not editable in place
07-strings / row.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>A row of characters</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const name = "Asha Reddy";
10
11 let out = "";
12 out += "length: " + name.length + "\n";
13 out += "first: " + name[0] + "\n";
14 out += "last: " + name[name.length - 1] + "\n";
15 out += "at 5: " + name[5] + "\n\n";
16
17 name[0] = "M";
18 out += "after trying to change position 0:\n" + name;
19
20 document.getElementById("out").innerHTML = out;
21 </script>
22</body>
23</html>
untitled×
127.0.0.1:5500/index.html
live
line 17 tried to change the A. Look at the last line.
Positions work exactly like an array. name[0] is the first character, name.length - 1 the last. You already know this shape from Module 6.
Spaces are characters. "Asha Reddy" is ten long, not nine. This matters enormously when you are counting what somebody typed.
Assigning to a position does nothing. No error, no warning, no change. Strings cannot be edited in place — every method you are about to meet hands you a new string and leaves the original alone.
Every string method makes a new string.
None of them change the one you started with.
CHUNK 2 OF 4 0:08 – 0:17

The methods the papers actually use

There are dozens of string methods. Nine of them cover every question your papers have ever asked. Here they all are on one string, so you can see what each hands back.
07-strings / methods.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>String methods</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const raw = " Dr. Asha Reddy ";
10
11 let out = "";
12 out += "[" + raw + "]\n";
13 out += "[" + raw.trim() + "] <-- trim\n\n";
14
15 const s = raw.trim();
16 out += s.toUpperCase() + " <-- toUpperCase\n";
17 out += s.toLowerCase() + " <-- toLowerCase\n";
18 out += s.slice(0, 3) + " <-- slice(0,3)\n";
19 out += s.indexOf(" ") + " <-- indexOf(space)\n";
20 out += s.split(" ") + " <-- split(space)\n";
21 out += s.replace("Asha", "Meera") + " <-- replace\n";
22 out += s.includes("Reddy") + " <-- includes\n";
23 out += s.startsWith("Dr.") + " <-- startsWith\n\n";
24
25 out += "original is untouched:\n[" + raw + "]";
26
27 document.getElementById("out").innerHTML = out;
28 </script>
29</body>
30</html>
untitled×
127.0.0.1:5500/index.html
live
nine methods, one string — and it is unchanged at the end
Line 9 has spaces at both ends on purpose. The square brackets in the output are there so you can see them — they are not part of the string.
Line 13 trims once and keeps the result. Everything after works on the clean copy. That is the pattern: clean first, then work.
Every line hands back something new. Not one of them changes s, which is why the last line can still print the original with its spaces intact.
split(" ") is the odd one out. It hands back an array, not a string — three items here. Everything else on this list gives you text or true/false.
Method
What it hands back
You will use it to
trim()
the same text without spaces at either end
always — clean what the user typed
toUpperCase()
an all-capitals copy
display, and case-blind comparison
slice(a, b)
the piece from a up to but not including b
cut a title or a code out
indexOf(x)
the position of x, or −1 if absent
find where something starts
split(x)
an array, cut wherever x appears
break a full name into parts
replace(a, b)
a copy with the first a swapped for b
swap a word out
includes(x)
true or false
check something is present
startsWith(x)
true or false
check a prefix — Module 10 uses this
In our code
line 13 trims the spaces off
every later line works on the clean copy
Two things that catch people. indexOf returns −1 when it finds nothing — not 0, not false. And replace only swaps the first match; to change all of them you need replaceAll.
trim() first, every single time. A user who types a trailing space has typed something different from what they think. Almost every "my validation rejects a correct answer" complaint comes down to a space nobody can see.

Look-alikes, and how they differ

07-strings / compare.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Look-alikes</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 const s = "Asha Reddy";
10
11 let out = "";
12 out += "charAt(0) " + s.charAt(0) + "\n";
13 out += "s[0] " + s[0] + "\n";
14 out += "charAt(99) [" + s.charAt(99) + "]\n";
15 out += "s[99] " + s[99] + "\n\n";
16 out += "slice(0, 4) " + s.slice(0, 4) + "\n";
17 out += "substring(0, 4) " + s.substring(0, 4) + "\n";
18 out += "slice(-5) " + s.slice(-5) + "\n";
19 out += "substring(-5) " + s.substring(-5) + "\n\n";
20 out += "concat " + s.concat("!") + "\n";
21 out += "plus " + (s + "!") + "\n";
22 out += "template " + `${s}!` + "\n\n";
23 out += "indexOf d " + s.indexOf("d") + "\n";
24 out += "lastIndexOf d " + s.lastIndexOf("d") + "\n";
25 out += "indexOf z " + s.indexOf("z") + "\n";
26 out += "repeat(10) " + "-".repeat(10);
27
28 document.getElementById("out").innerHTML = out;
29 </script>
30</body>
31</html>
untitled×
127.0.0.1:5500/index.html
live
look-alike methods, run side by side
Method
One-line example
Result
charAt(i) vs s[i]
s.charAt(0)   s[0]
both "A"; past the end, "" against undefined
slice(a, b) vs substring(a, b)
s.slice(-5)   s.substring(-5)
same for (0, 4); a negative slice counts from the end ("Reddy"), substring treats it as 0 ("Asha Reddy")
concat vs + vs backticks
s.concat("!")   s + "!"   `${s}!`
all three give "Asha Reddy!" — write backticks
indexOf(x)
s.indexOf("d")   s.indexOf("z")
7, and −1 when it is missing
lastIndexOf(x)
s.lastIndexOf("d")
8 — the search starts from the end
repeat(n)
"-".repeat(10)
"----------"
In our code
s is "Asha Reddy"
every result above is printed in the frame
CHUNK 3 OF 4 0:17 – 0:28

The exam question, in full

PYQ · 15252 (S) N · Q12(b) · 4 marks
“Develop a JavaScript function to manipulate string data (i) to generate full name using first-name and last-name given as input (ii) extract salutation like Dr./Mr./Ms. from the author name given as input.”
Two functions, two marks each. The first joins; the second cuts. Both use nothing beyond the nine methods from the last chunk. Type in the frame and press the button.
07-strings / names.html
the head and styles1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Name tools</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 label { display: block; margin-bottom: 12px; }
9 input { padding: 8px; width: 200px; }
10 button { padding: 8px 16px; background: skyblue; }
11 </style>
12</head>
three boxes and a button13<body>
14 <h3>Name tools</h3>
15
16 <label>First name</label>
17 <input id="fn" value="asha">
18
19 <label>Last name</label>
20 <input id="ln" value="reddy">
21
22 <label>Author name</label>
23 <input id="au" value="Dr. Kanetkar">
24
25 <button id="go">Run both</button>
26 <p id="out"></p>
27
part (i) joining · part (ii) cutting28 <script>
29 const fullName = (first, last) =>
30 first.trim() + " " + last.trim();
31
32 const salutation = who => {
33 const titles = ["Dr.", "Mr.", "Ms.", "Mrs."];
34 const first = who.trim().split(" ")[0];
35 return titles.includes(first) ? first : "none";
36 };
37
38 document.getElementById("go").onclick = () => {
reading them on click39 const f = document.getElementById("fn").value;
40 const l = document.getElementById("ln").value;
41 const a = document.getElementById("au").value;
42
43 document.getElementById("out").innerHTML =
44 `Full name: ${fullName(f, l)}<br>Salutation: ${salutation(a)}`;
45 };
46 </script>
47</body>
48</html>
untitled×
127.0.0.1:5500/index.html
live
try changing the author to a name with no title
fullName trims both halves before joining. Without that, a stray space in the first-name box gives you "asha reddy" with a double gap.
salutation splits on the space and takes piece 0. "Dr. Kanetkar" becomes ["Dr.", "Kanetkar"], and position 0 is the candidate title.
Then it checks that candidate against a known list. titles.includes(first) — the array method from Module 6 doing string work. This is better than checking for a full stop, because "A. Kanetkar" would fool that.
The ? : is a compact if-else. test ? valueIfTrue : valueIfFalse. It fits in a return line, which is the only reason to prefer it. A normal if earns identical marks.
Note <br> inside the backticks on line 43. Because we are setting innerHTML, the browser reads that as a real line break. A \n would do nothing here — that only works inside a <pre>, which is what the earlier examples used.
CHUNK 4 OF 4 0:28 – 0:36

Rejecting what you do not want

PYQ · 15279 N/O · Q12(a) · 4 marks
“Write a JavaScript program to read the text from an input text box, convert the text to uppercase and display the result inside a <p> tag when a button is clicked. If the text entered contains numbers or special characters @, # or $ display the error message below the text box in red color.”
This is your first full validation question, and it has the shape all seven of them share: read, test, then either show an error or do the job. Try typing hello123 in the frame.
07-strings / shout.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Shout it</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 input { padding: 8px; width: 220px; }
9 button { padding: 8px 16px; background: skyblue; }
10 .error { color: red; font-size: 13px; }
11 </style>
12</head>
13<body>
14 <h3>Make it shout</h3>
15
16 <input id="txt" value="hello vasavi">
17 <button id="go">Convert</button>
18
19 <p class="error" id="err"></p>
20 <p id="out"></p>
21
22 <script>
23 const BAD = ["@", "#", "$"];
24
25 document.getElementById("go").onclick = () => {
26 const text = document.getElementById("txt").value.trim();
27 const err = document.getElementById("err");
28 const out = document.getElementById("out");
29
30 const hasDigit = /[0-9]/.test(text);
31 const hasSymbol = BAD.some(c => text.includes(c));
32
33 if (hasDigit || hasSymbol) {
34 err.innerHTML = "No numbers or @ # $ please";
35 out.innerHTML = "";
36 return;
37 }
38
39 err.innerHTML = "";
40 out.innerHTML = text.toUpperCase();
41 };
42 </script>
43</body>
44</html>
untitled×
127.0.0.1:5500/index.html
live
type a digit or an @ and press Convert
Read, then test, then decide. Line 26 reads and trims. Lines 30 and 31 test. Line 33 decides. Every validation answer in Modules 9 and 10 follows those three steps.
/[0-9]/.test(text) asks "is there any digit in here?" The slashes make a pattern, and [0-9] means any single digit. Module 9 teaches patterns properly — for now, read it as a question that answers true or false.
BAD.some(c => text.includes(c)) asks "is any of these three in here?" some is an array method — true if at least one item passes. A cousin of filter from Module 6.
The early return on line 36 stops there. Show the error, clear the old result, leave. Without it the code would carry on and shout the bad text anyway.
Clearing matters as much as showing. Line 39 empties the error before a good run. Forget it and a fixed mistake keeps its red message forever — the single most common bug in validation answers.
Step
The line
Why it is there
Read
.value.trim()
get what was typed, minus invisible spaces
Test
hasDigit, hasSymbol
two separate questions, each true or false
Reject
if (hasDigit || hasSymbol)
|| means or — either one is enough to refuse
Stop
return;
leave now, so the good path never runs
Clear
err.innerHTML = ""
wipe an old error before showing a new result
In our page
type hello123
red message, no output — try it in the frame

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-first-script · 03-variables · 04-functions · 05-objects · 06-arrays └── 07-strings ├── row.html new ├── methods.html new ├── compare.html new ├── names.html new └── shout.html new

Practice

1From "1602-24-733-001@vce.ac.in", pull out the roll number and the domain separately. Do it two ways.
Show the solution
07-strings / split.htmlruns
1<script>
2 const email = "1602-24-733-001@vce.ac.in";
3
4 const at = email.indexOf("@");
5 const roll = email.slice(0, at);
6 const domain = email.slice(at + 1);
7
8 console.log(roll);
9 console.log(domain);
10 console.log(email.split("@"));
11</script>
untitled×
127.0.0.1:5500/index.html
live
slice needs you to find the @ first; split does both jobs in one call and hands back both halves. For a single separator, split is almost always the shorter answer — but slice is what you need when the cut point is a count rather than a character.
2Why does this print false, and what are two ways to fix it?
const typed = " ASHA ";
console.log(typed === "Asha");
Show the solution
Two problems, both invisible on screen. There are spaces at each end, and the capitals do not match.

Fix one — clean before comparing:
typed.trim().toLowerCase() === "asha"
Fix two — if you only care about the letters being there:
typed.trim().toLowerCase().includes("asha")
The habit: trim and lower-case both sides before comparing text a human typed. You cannot see a trailing space, and neither can they.
3A student writes name.toUpperCase(); on its own line and wonders why the name is still lower case. Explain.
Show the solution
Because strings cannot be changed in place. toUpperCase() did its work perfectly — it made a capitalised copy and handed it back. Nobody caught it, so it was thrown away.

Fix: name = name.toUpperCase(); — or store it somewhere new. This applies to every string method: trim, slice, replace, all of them.

Compare with arrays: marks.push(5) genuinely changes the array. name.toUpperCase() cannot change the string. That difference catches everybody once.
You have just written your first validation. Next: how the button knew you clicked it — the piece that has been quietly doing the work since Module 2.
Module 8 · Events and Event Handling · 34 min
CHUNK 1 OF 4 0:00 – 0:08

Waiting for something to happen

Covering the syllabus phrase: Event Handling
You have been using this since Module 2 without naming it. Every onclick you wrote was an event handler. Here is what was actually going on.
New folder 08-events inside FSWD-Unit2 · new files bell.html · three.html · typo.html · watch.html · form.html · target.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
An event
Something that happens — a click, a key press, a form being submitted, the page finishing loading. The browser notices all of them, all the time, whether you are listening or not.
A handler
Instructions you leave with the browser: “if this happens, run that.” Like fitting a doorbell — you install it once and walk away. It does nothing until somebody presses it.
08-events / bell.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>The doorbell</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 button { padding: 8px 16px; background: skyblue; }
9 </style>
10</head>
11<body>
12 <button id="bell">Ring the bell</button>
13 <p id="out">nobody has rung yet</p>
14
15 <script>
16 let count = 0;
17
18 document.getElementById("bell").addEventListener("click", () => {
19 count = count + 1;
20 document.getElementById("out").innerHTML =
21 `rung ${count} time` + (count === 1 ? "" : "s");
22 });
23
24 console.log("script finished — but nothing has run yet");
25 </script>
26</body>
27</html>
untitled×
127.0.0.1:5500/index.html
live
press it a few times — the count is remembered
1 · INSTALL addEventListener happens once, on load 2 · WAIT nothing runs. could be forever. 3 · FIRE somebody clicks — now it runs back to waiting — step 3 can happen any number of times step 1 never repeats
Install once · wait · fire on every click · the install never runs again
Line 23 prints immediately; the handler does not. Open the console and you will see the message the moment the page loads — before you have touched anything. The instructions inside the handler are stored, not run.
count lives outside the handler. That is why it remembers. If it were declared inside, it would be created fresh at 0 on every single click.
The handler can run any number of times — or none. Nobody clicks, nothing happens, no error. That is normal.
Line
When it runs
How many times
let count = 0
as the page loads
once
addEventListener(...)
as the page loads
once — it only installs
the arrow function inside it
every click
as many times as you press
console.log(...) on line 23
as the page loads
once — before any click
In our page
press the bell three times
the count reaches 3, because count lives outside
Installing a handler is not running it.
You leave instructions and walk away.
CHUNK 2 OF 4 0:08 – 0:17

Three ways to attach, and which one wins

There are three ways to say “when this is clicked, do that”. You need to read all three, because your question papers use the older ones. You should write the third.
08-events / three.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Three ways to attach</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 button { padding: 8px 14px; background: skyblue; margin-right: 6px; }
9 </style>
10</head>
11<body>
12 <button onclick="say('attribute')">A</button>
13 <button id="b2">B</button>
14 <button id="b3">C</button>
15 <p id="out"></p>
16
17 <script>
18 function say(which) {
19 document.getElementById("out").innerHTML = "fired by: " + which;
20 }
21
22 document.getElementById("b2").onclick = () => say("property");
23
24 document.getElementById("b3").addEventListener("click",
25 () => say("addEventListener"));
26
27 document.getElementById("b3").addEventListener("click",
28 () => console.log("a second listener on the same button"));
29 </script>
30</body>
31</html>
untitled×
127.0.0.1:5500/index.html
live
press each button — then press C and check the console
Way
Written as
The catch
1. attribute
<button onclick="say()">
JavaScript inside your HTML — hard to find later
2. property
btn.onclick = fn
only one at a time — a second assignment replaces the first
3. listener
btn.addEventListener("click", fn)
none worth mentioning — use this
In our page
button C has two listeners
both run — the property way could not do that
The trap in way 2. btn.onclick = fn is an ordinary assignment into a box, so writing it twice throws the first away — silently. If two people add a handler to the same button, one of them loses. addEventListener stacks them instead, which is the entire reason it exists.
Your papers use way 2, and that is fine. Every worked answer in this course uses onclick = because it is shorter under exam pressure and marks the same. Use addEventListener in the lab, where two handlers on one element eventually happens.
One more, and it catches everybody once. Write btn.onclick = say() with brackets and you have called say immediately and stored whatever it returned — usually undefined. Then nothing happens when you click. No brackets when handing a function over; brackets only when you want it to run now. Same lesson as student.average in Module 5.

When the id is misspelt

08-events / typo.html  — one letter wrongruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>One letter wrong</title></head>
5<body>
6 <button id="button">Ring the bell</button>
7 <p id="err" style="color: red;"></p>
8 <script>
9 window.addEventListener("error", e => {
10 document.getElementById("err").innerHTML = e.message;
11 });
12 </script>
13 <script>
14 document.getElementById("buton").addEventListener("click", () => {
15 alert("ding");
16 });
17 </script>
18</body>
19</html>
untitled×
127.0.0.1:5500/index.html
live
the button is there; the script never reached it
The id has a typo, so there is nothing to attach to. getElementById("buton") finds no element and hands back null, and null has no addEventListener — that is all the red line is saying. Match the spelling to the HTML and the bell works. Lines 9 to 13 only copy the console’s message onto the page so you can read it here.
CHUNK 3 OF 4 0:17 – 0:27

The events this unit needs

The browser fires dozens of different events. Six of them cover everything your papers ask for. Type in the box below and watch them arrive.
08-events / watch.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Which events</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 input { padding: 8px; width: 200px; }
9 pre { background: #f4f4f4; padding: 8px; }
10 </style>
11</head>
12<body>
13 <h3>Watch the events fire</h3>
14
15 <input id="box" placeholder="type here, then click away">
16
17 <select id="pick">
18 <option>Dosa</option>
19 <option>Idli</option>
20 </select>
21
22 <pre id="log"></pre>
23
24 <script>
25 const log = document.getElementById("log");
26 const note = what => { log.innerHTML = what + "\n" + log.innerHTML; };
27
28 const box = document.getElementById("box");
29
30 box.addEventListener("input", () => note("input - every keystroke"));
31 box.addEventListener("blur", () => note("blur - you left the box"));
32 box.addEventListener("keyup", () => note("keyup - a key came up"));
33
34 document.getElementById("pick")
35 .addEventListener("change", () => note("change - dropdown changed"));
36
37 window.addEventListener("load", () => note("load - page finished"));
38 </script>
39</body>
40</html>
untitled×
127.0.0.1:5500/index.html
live
type, then click outside the box, then change the dropdown
Event
Fires when
Used in the papers for
click
a button or element is pressed
almost every question
input
every keystroke in a text box
validating as the user types
blur
focus leaves a field
“after the control is moved from the last name”
change
a dropdown or checkbox is altered
“display the price based on the course selected”
submit
a form is sent
validating everything at once
load
the page has finished building
a rescue for a script placed too early
In our page
the log fills from the top
notice input and keyup both fire per key
That last one says window, not document. A page finishing loading happens to the tab, not to any element inside it. Module 12 covers the window object properly.
blur is the one the papers name without naming. Whenever a question says “immediately after the control is moved from the last name” or “when the user leaves the field”, that is blur. Module 9 answers exactly that question.

Every event you are likely to meet, one line each

Event
Fires when
One-line example
click
an element is pressed once
btn.addEventListener("click", ring)
dblclick
it is pressed twice, quickly
photo.addEventListener("dblclick", zoom)
input
every keystroke in a box
box.addEventListener("input", check)
change
a dropdown or checkbox is altered
course.addEventListener("change", price)
submit
a form is sent
form.addEventListener("submit", send)
focus / blur
a field is entered / left
last.addEventListener("blur", join)
keydown / keyup
a key goes down / comes back up
box.addEventListener("keyup", count)
mouseover / mouseout
the pointer moves onto / off an element
card.addEventListener("mouseover", glow)
load
the page and its images have finished
window.addEventListener("load", start)
In our page
type in the box above
input and keyup arrive for every key
CHUNK 4 OF 4 0:27 – 0:34

The event object, and stopping the page reloading

Module 0 opened with a page that vanished and came back when you pressed submit. That is still what a form does by default. Here is the one line that stops it — and it is the line students most often leave out.
08-events / form.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Stop the reload</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 input { padding: 8px; width: 200px; }
9 button { padding: 8px 16px; background: skyblue; }
10 .error { color: red; font-size: 13px; }
11 </style>
12</head>
13<body>
14 <form id="f">
15 <input id="who" placeholder="your name">
16 <button>Send</button>
17 </form>
18
19 <p class="error" id="err"></p>
20 <p id="out"></p>
21
22 <script>
23 document.getElementById("f")
24 .addEventListener("submit", event => {
25 event.preventDefault();
26
27 const name = document.getElementById("who").value.trim();
28
29 if (name === "") {
30 document.getElementById("err").innerHTML = "Name is required";
31 return;
32 }
33
34 document.getElementById("err").innerHTML = "";
35 document.getElementById("out").innerHTML = "Thanks, " + name;
36 });
37 </script>
38</body>
39</html>
untitled×
127.0.0.1:5500/index.html
live
press Send with the box empty, then with a name
The handler now takes an argument: event. The browser hands it in automatically, every time. It carries details about what just happened — which key, which element, where the mouse was.
event.preventDefault() cancels what the browser would normally do. For a form, that is sending it away and reloading. Take that line out and the page blanks the instant you press Send.
Then the same three steps as Module 7: read the value, test it, either show an error and return, or clear the error and do the job.
submit is on the form, not the button. That way pressing Enter in the text box works too — which is what people actually do.
The symptom to recognise: you press Send, the page flashes, everything resets, and your error message appears for a split second before vanishing. That is a missing preventDefault(), every time. It is the single most common bug in form-validation answers.

Which button was it? event.target

A click does not stay where it lands. It rises through every box the button sits inside, like a bubble — which is why this is called bubbling. So one listener on the outer box hears all of its buttons, and event.target says which one started it.
08-events / target.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Which one?</title></head>
5<body>
6 <div id="menu">
7 <button>Dosa</button>
8 <button>Idli</button>
9 <button>Vada</button>
10 </div>
11 <p id="out">press any button</p>
12
13 <script>
14 document.getElementById("menu").addEventListener("click", event => {
15 if (event.target.tagName !== "BUTTON") return;
16 document.getElementById("out").innerHTML =
17 "You clicked " + event.target.textContent;
18 });
19 </script>
20</body>
21</html>
untitled×
127.0.0.1:5500/index.html
live
press any of the three — one listener answers them all
body div id="menu" button · Idli 1 · lands on the button 2 · rises to the div, listener runs 3 · keeps rising to body
Lands on the button · rises through every box around it · one listener on the div hears all three
One listener, on the div, instead of three on the buttons. The click lands on a button, rises to the div, and the handler runs there.
event.target is where the click started — the button itself — and textContent reads its label.
Line 15 ignores a click on the gap between buttons. There the target is the div, not a BUTTON.
event.stopPropagation() stops the rise. Called inside a handler, it keeps that click from reaching the boxes further out.
A form’s default job is to leave the page.
One line tells it to stay.

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-first-script · 03-variables · 04-functions · 05-objects · 06-arrays · 07-strings └── 08-events ├── bell.html new ├── three.html new ├── typo.html new ├── watch.html new ├── form.html new └── target.html new

Practice

1A colour box should update a paragraph as you type, not when you finish. Which event, and why not change?
Show the solution
box.addEventListener("input", () => {
  out.innerHTML = box.value;
});
input fires on every keystroke. change on a text box only fires when you leave it, so nothing would happen while typing. On a dropdown they behave much the same; on a text box they are very different.
2Two people add a handler to the same button, one writing btn.onclick = a and the other btn.onclick = b. What happens, and how should they have done it?
Show the solution
Only b runs. The second assignment overwrote the first, silently — no error, no warning. a is gone.

The fix: both should use btn.addEventListener("click", a) and btn.addEventListener("click", b). Listeners stack; both run, in the order they were added.

Why this matters beyond exams: in a real page, handlers get added from several places. The property form makes that a race nobody notices until something stops working.
3A student’s validation works, but the page reloads and the error disappears instantly. Diagnose it in one sentence.
Show the solution
The submit handler is missing event.preventDefault().

The validation ran correctly and wrote the message. Then the browser did what a form does by default — sent it and loaded a fresh page, wiping everything including the message.

Two ways to fix it: take event into the handler and call event.preventDefault() as the first line, or move the handler to the button’s click instead of the form’s submit. The first is better — it keeps Enter working.
You now have every piece a validation question needs. Values, functions, strings, events, and a form that stays put. The next two modules put them together, seven times over.
Module 9 · Form Validation, Foundations · 40 min
CHUNK 1 OF 5 0:00 – 0:07

Catching mistakes before they matter

This is the most-asked topic in your papers — seven questions across four papers. This module and the next cover every pattern they have used.
New folder 09-validation inside FSWD-Unit2 · new files blank.html · password.html · fullname.html · pattern.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
A form with no checking will accept anything. An empty name, an email with no @, a date of birth in the future. Once that reaches the server it is somebody else’s problem, and usually a permanent one.
NO CHECKING the form (empty) the network the server the database a nameless student, forever WITH CHECKING the form Name is required it never leaves the page nothing to clean up later
The cheapest place to catch a mistake is the one where it was made

The shape every one of the seven questions shares

09-validation / blank.htmlruns
the page and its styles1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Admission form</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 label { display: block; margin-bottom: 12px; }
9 input { padding: 8px; width: 200px; }
10 button { padding: 8px 16px; background: skyblue; }
11 .error { color: red; font-size: 13px; }
12 </style>
13</head>
one field, one error line14<body>
15 <h3>Admission form</h3>
16
17 <label>Your name</label>
18 <input id="who">
19 <p class="error" id="err"></p>
20
21 <button id="go">Submit</button>
22 <p id="out"></p>
23
read, test, decide24 <script>
25 document.getElementById("go").onclick = () => {
26 const who = document.getElementById("who").value.trim();
27 const err = document.getElementById("err");
28 const out = document.getElementById("out");
29
30 if (who === "") {
31 err.innerHTML = "Name is required";
32 out.innerHTML = "";
33 return;
34 }
35
36 err.innerHTML = "";
37 out.innerHTML = "Saved: " + who;
38 };
39 </script>
40</body>
41</html>
untitled×
127.0.0.1:5500/index.html
live
press Submit with the box empty, then with a name
Read. .value gets what was typed. .trim() removes the invisible spaces — without it, a single space would count as a name.
Test. One condition per rule. Here it is who === "". In the next chunks it will be a comparison, a length, a pattern — but always one clear question.
Reject. Write the message, clear any old result, and return. The return is what stops the good path running anyway.
Accept. Clear the error first, then do the job. Skip the clearing and a fixed mistake keeps its red message forever.
Read · test · reject · accept.
Seven exam questions, one shape.
CHUNK 2 OF 5 0:07 – 0:15

More than one field, more than one rule

One field was a warm-up. Real forms have several, each with its own message, and all of them must be checked before anything is accepted. Here is the pattern that scales, and it is the one every remaining question uses.
09-validation / rules.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Three rules</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 label { display: block; margin-bottom: 4px; }
9 input { padding: 8px; width: 200px; }
10 button { padding: 8px 16px; background: skyblue; }
11 .error { color: red; font-size: 13px; min-height: 16px; }
12 </style>
13</head>
each field gets its own error line14<body>
15 <h3>Three rules</h3>
16
17 <label>Name</label>
18 <input id="nm">
19 <p class="error" id="eNm"></p>
20
21 <label>Age</label>
22 <input id="ag">
23 <p class="error" id="eAg"></p>
24
25 <button id="go">Submit</button>
26 <p id="out"></p>
one helper, then one check per field27
28 <script>
29 const show = (id, msg) => {
30 document.getElementById(id).innerHTML = msg;
31 return msg === "";
32 };
33
34 document.getElementById("go").onclick = () => {
35 const nm = document.getElementById("nm").value.trim();
36 const ag = document.getElementById("ag").value.trim();
37
38 const okNm = show("eNm",
39 nm === "" ? "Name is required" :
40 nm.length < 3 ? "At least 3 letters" : "");
41
42 const okAg = show("eAg",
43 ag === "" ? "Age is required" :
44 Number(ag) < 17 ? "Must be 17 or older" : "");
45
46 document.getElementById("out").innerHTML =
47 (okNm && okAg) ? "Saved" : "";
48 };
49 </script>
50</body>
51</html>
untitled×
127.0.0.1:5500/index.html
live
try an empty name, a two-letter name, and an age of 15
Every field gets its own <p class="error">. One shared message box cannot tell the user which field is wrong, and the papers mark you down for that.
min-height: 16px on the error line. Without it the page jumps up and down as messages appear and vanish. A small thing that makes a form feel finished.
The show helper does two jobs. It writes the message, and it hands back true when the message is empty — meaning that field passed. Writing and answering in one call keeps the checks short.
The stacked ? : reads as a list of rules. Empty? that message. Too short? that one. Otherwise empty string, meaning fine. Rules are tested in order, and the first one that matches wins.
okNm && okAg — both must pass. && means and. Note both checks run before this line, so every wrong field shows its message at once, not one at a time.
Line
What it does
Leave it out and…
min-height
reserves room for the error line
the page jumps as messages appear
show(id, msg)
writes the message and reports pass/fail
you write both jobs out twice per field
.trim()
drops invisible spaces
a single space counts as a valid name
Number(ag)
turns the text into a number
"9" < "17" is false — the check silently misfires
both checks before the if
every wrong field reports at once
the user finds their errors one at a time
In our page
empty name, age 15
both messages appear together
The tempting shortcut that costs marks. Writing if (nm === "") { show(...); return; } for each field means the user fixes one error, presses Submit, and is told about the next one. Three fields, three rounds. Check them all, then decide.
Number(ag) < 17, not ag < 17. A text box hands back text, and comparing text to a number gives answers you did not expect — "9" < 17 happens to be true, but "9" < "17" is false. Convert first, every time. Module 13 explains why.
CHUNK 3 OF 5 0:15 – 0:24

Password and re-type password

PYQ · 15259 N · Q3 · 2 marks
“Write JavaScript code to validate password and re-type password fields.”
Two marks, and the second one is the one people miss. Mark one is comparing the two. Mark two is handling the cases around it — either box empty, or the password too short. A bare if (p1 !== p2) is half an answer.
09-validation / password.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Set a password</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 label { display: block; margin-bottom: 4px; }
9 input { padding: 8px; width: 200px; }
10 button { padding: 8px 16px; background: skyblue; }
11 .error { color: red; font-size: 13px; min-height: 16px; }
12 .ok { color: green; font-size: 13px; }
13 </style>
14</head>
two boxes, two error lines15<body>
16 <h3>Set a password</h3>
17
18 <label>Password</label>
19 <input id="p1" type="password">
20 <p class="error" id="e1"></p>
21
22 <label>Re-type password</label>
23 <input id="p2" type="password">
24 <p class="error" id="e2"></p>
25
26 <button id="go">Save</button>
27 <p class="ok" id="out"></p>
the rules, in order28
29 <script>
30 document.getElementById("go").onclick = () => {
31 const p1 = document.getElementById("p1").value;
32 const p2 = document.getElementById("p2").value;
33
34 const m1 = p1 === "" ? "Password is required" :
35 p1.length < 8 ? "At least 8 characters" : "";
36
37 const m2 = p2 === "" ? "Please re-type it" :
38 p1 !== p2 ? "The two do not match" : "";
39
40 document.getElementById("e1").innerHTML = m1;
41 document.getElementById("e2").innerHTML = m2;
42
43 document.getElementById("out").innerHTML =
44 (m1 === "" && m2 === "") ? "Password saved" : "";
45 };
46 </script>
47</body>
48</html>
untitled×
127.0.0.1:5500/index.html
live
type two different passwords, then make them match
No .trim() here, and that is deliberate. A space is a perfectly legal password character. Trimming would quietly change what the user chose — the one place in this unit where trimming is wrong.
type="password" hides the characters as dots. It changes nothing about how you read the value; it only stops somebody behind them reading the screen.
Length before match. If the password is only three characters, telling the user the two do not match is unhelpful noise. Check the first box is valid on its own, then check the pair.
p1 !== p2 uses three characters, not two. !== is “not exactly equal”. Module 13 explains why the two-character version would be a bad idea here.
What the user did
Which message
Why that one
left both empty
both boxes complain
each field owns its own message
typed abc twice
“At least 8 characters”
they match, but the first rule failed first
typed vasavi2026 then vasavi2025
“The two do not match”
length passed, so the pair check ran
In our page
fix both and press Save
green Password saved, no reload
CHUNK 4 OF 5 0:24 – 0:32

Filling a box the moment you leave another

PYQ · 15259 N · Q12(b) · 4 marks
“Write a JavaScript program to read first name and last name from the user through a form. Generate full name in another text box in the same page dynamically immediately after the control is moved from the last name. Ensure first name and last name should accepts only alphabets and cannot be blank.”
“Immediately after the control is moved from” is the exam’s way of saying blur. No button anywhere in this question — the work happens when focus leaves the field. That is the mark most answers lose.
09-validation / fullname.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Full name</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 label { display: block; margin-bottom: 4px; }
9 input { padding: 8px; width: 200px; }
10 .error { color: red; font-size: 13px; min-height: 16px; }
11 </style>
12</head>
two boxes, plus one the user cannot type in13<body>
14 <h3>Admission &mdash; your name</h3>
15
16 <label>First name</label>
17 <input id="fn">
18 <p class="error" id="e1"></p>
19
20 <label>Last name</label>
21 <input id="ln">
22 <p class="error" id="e2"></p>
23
24 <label>Full name</label>
25 <input id="full" readonly>
one rule, reused for both fields26
27 <script>
28 const onlyLetters = t => /^[A-Za-z]+$/.test(t);
29
30 const checkOne = (boxId, errId) => {
31 const t = document.getElementById(boxId).value.trim();
32 const msg = t === "" ? "This cannot be blank" :
33 !onlyLetters(t) ? "Letters only" : "";
34 document.getElementById(errId).innerHTML = msg;
build on blur35 return msg === "";
36 };
37
38 const build = () => {
39 const okF = checkOne("fn", "e1");
40 const okL = checkOne("ln", "e2");
41
42 document.getElementById("full").value = (okF && okL)
43 ? document.getElementById("fn").value.trim() + " " +
44 document.getElementById("ln").value.trim()
45 : "";
46 };
47
48 document.getElementById("fn").addEventListener("blur", build);
49 document.getElementById("ln").addEventListener("blur", build);
50 </script>
51</body>
52</html>
untitled×
127.0.0.1:5500/index.html
live
type a first name, press Tab, then a last name and Tab again
blur fires when focus leaves a field — pressing Tab, or clicking elsewhere. Module 8 showed it in the event log; this is what it is for.
readonly on the full-name box. The user should not type there; only the script fills it. It still looks like a field and its value can still be read and submitted.
/^[A-Za-z]+$/ is a pattern, and the next chunk takes it apart properly. For now: ^ means start, $ means end, [A-Za-z] means one letter, + means one or more. Together: letters from beginning to end, nothing else.
checkOne is written once and used twice. Two fields with the same rule should not mean two copies of the rule — that is what a function is for, and markers notice.
The full-name box is cleared when either field is invalid. Leaving a stale full name on screen while an error shows underneath is worse than showing nothing.
Both fields get a blur handler, not only the last name. The question only mentions the last name, but a user who fixes the first name and tabs away expects the full name to update. Handling both is more correct and costs one line.
CHUNK 5 OF 5 0:32 – 0:40

Patterns, gently

Every remaining validation question — email, pincode, username, date — is a rule about the shape of some text. A pattern says that shape in one line. You need six pieces of the notation and no more.
/ … /
The slashes mark a pattern, the way quotes mark text. .test(value) asks “does this fit?” and answers true or false.
/^[A-Za-z]{3,}$/ ^ must start here [A-Za-z] any one letter {3,} three or more of them $ must end here read together: from start to end, three or more letters and nothing else
Four symbols · every validation pattern in your papers is built from these
Piece
Means
Which question uses it
^
the value must start here
“must start with an alphabet”
$
the value must end here
“must end with an alphabet”
[A-Za-z]
any one letter
“accepts only alphabets”
[0-9]
any one digit
pincode, roll number, date
{6}  {2,5}
exactly six · between two and five
“exactly 5 digits”, “size between 2 to 5”
+  *
one or more · zero or more
a name of any length
In our tester
type Asha1
“letters only” turns to no, “has a digit” to yes
09-validation / pattern.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Pattern tester</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 input { padding: 8px; width: 220px; }
9 pre { background: #f4f4f4; padding: 8px; }
10 </style>
11</head>
12<body>
13 <h3>Try a value</h3>
14 <input id="box" value="Asha">
15 <pre id="out"></pre>
16
six rules in one object17 <script>
18 const RULES = {
19 "letters only": /^[A-Za-z]+$/,
20 "digits only": /^[0-9]+$/,
21 "exactly 6 digits": /^[0-9]{6}$/,
22 "starts with a letter":/^[A-Za-z]/,
23 "ends with a letter": /[A-Za-z]$/,
24 "has a digit anywhere":/[0-9]/
25 };
test them all, live26
27 const test = () => {
28 const v = document.getElementById("box").value;
29 let out = "";
30 for (const name in RULES) {
31 out += (RULES[name].test(v) ? " yes " : " no ") + name + "\n";
32 }
33 document.getElementById("out").innerHTML = out;
34 };
35
36 document.getElementById("box").addEventListener("input", test);
37 test();
38 </script>
39</body>
40</html>
untitled×
127.0.0.1:5500/index.html
live
type in the box — every rule re-tests on each keystroke
Forget the ^ and $ and the rule stops being a rule. /[0-9]{6}/ without them says “six digits somewhere inside”, so abc123456xyz passes. With them it says “six digits and nothing else”. Almost every wrong pattern answer is a missing anchor.
The rules live in one object. A name and a pattern side by side, so the list reads like a table rather than six separate checks.
for (const name in RULES) walks the labels. The in loop hands you each key in turn — the same Object.keys idea from Module 5, in loop form.
test() is called once at the end, on line 33. Without that the panel would be blank until the first keystroke, which looks broken.
Try these in the box: Asha passes letters-only. 500031 passes digits-only and exactly-six. Asha1 fails letters-only but passes has-a-digit and starts-with-a-letter.

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-first-script · 03-variables · 04-functions · 05-objects · 06-arrays · 07-strings · 08-events └── 09-validation ├── blank.html new ├── rules.html new ├── password.html new ├── fullname.html new └── pattern.html new

Practice

1Validate a roll number in the format 1602-24-733-001 — four digits, two, three, three, joined by hyphens.
Show the solution
09-validation / roll.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Roll number</title></head>
5<body>
6 <input id="r" value="1602-24-733-001">
7 <p class="error" id="e"></p>
8 <button id="go">Check</button>
9
10 <script>
11 const ROLL = /^[0-9]{4}-[0-9]{2}-[0-9]{3}-[0-9]{3}$/;
12
13 document.getElementById("go").onclick = () => {
14 const v = document.getElementById("r").value.trim();
15 document.getElementById("e").innerHTML =
16 ROLL.test(v) ? "" : "Format must be 1602-24-733-001";
17 };
18 </script>
19</body>
20</html>
untitled×
127.0.0.1:5500/index.html
live
Read the pattern in pieces: ^ start, [0-9]{4} four digits, - a literal hyphen, [0-9]{2} two digits, and so on to $. A hyphen outside square brackets means an actual hyphen — no escaping needed.
2A student’s pincode check is /[0-9]{5}/ and it accepts my pin is 500031 ok. Why, and what is the fix?
Show the solution
Because there are no anchors. The pattern asks “are there five digits somewhere in here?” and there are — so it passes.

The fix: /^[0-9]{5}$/. Now it means “from the very start to the very end, exactly five digits and nothing else”.

How to remember: without anchors a pattern searches; with anchors it measures. Validation almost always wants to measure.
3A form validates correctly, but users complain they have to press Submit three times to find all their mistakes. What is wrong with the code?
Show the solution
It returns after the first failure. Something like if (a bad) { show; return; } if (b bad) { show; return; } — the first return stops everything, so the user never learns about field two until field one is fixed.

The fix is the pattern from chunk 2: work out every message first, write them all, then decide whether to accept.
const okA = show("eA", ruleA());
const okB = show("eB", ruleB());
if (okA && okB) { /* accept */ }
Why it matters beyond marks: a form that reveals one problem at a time is genuinely unpleasant to use, and every examiner has filled one in.
You can now check a field, report it properly, and describe a shape in one line. The next module does nothing new — it applies exactly this, five more times, to every rule your papers have ever asked for.
Module 10 · Form Validation, Every PYQ Pattern · 40 min
CHUNK 1 OF 5 0:00 – 0:07

One form, five rules

Nothing new is taught in this module. Module 9 gave you the shape; this applies it to every validation rule your papers have asked for — five questions across four years, one form.
New folder 10-registration inside FSWD-Unit2 · one file register.html, grown across all five chunks · Ctrl+N then Ctrl+S, name it with .html · keep it open — every chunk adds to the same file
You will build a single registration form and add a field to it in each chunk. By the end it has five fields, five rules, and answers five past questions. Keep the same file open throughout.
CHUNK 1 email, rule one CHUNK 2 college email CHUNK 3 date of birth, pincode CHUNK 4 username CHUNK 5 courses one file · five fields · five past questions
The same file, grown five times
PYQ · 15267 N/O · Q3 · 2 marks
“Write JavaScript code to validate an email-id. The validation constraints are it must start with an alphabet, can contain alphabets and digits with size between 2 to 5 characters followed by yahoo.com.”
Read the question as a shape. One letter, then between one and four more letters or digits — that is 2 to 5 characters in total — then @yahoo.com and nothing after it.
10-registration / register.htmlruns
the page and the shared styles1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Registration</title>
6 <style>
7 body { font-family: Arial; max-width: 420px; }
8 label { display: block; margin-bottom: 4px; }
9 input { padding: 8px; width: 240px; }
10 button { padding: 8px 16px; background: skyblue; }
11 .error { color: red; font-size: 13px; min-height: 16px; }
12 .ok { color: green; }
13 </style>
14</head>
one field, for now15<body>
16 <h3>Registration</h3>
17
18 <label>Email</label>
19 <input id="mail" value="asha12@yahoo.com">
20 <p class="error" id="eMail"></p>
21
22 <button id="go">Register</button>
23 <p class="ok" id="out"></p>
24
the helper from Module 925 <script>
26 const show = (id, msg) => {
27 document.getElementById(id).innerHTML = msg;
28 return msg === "";
29 };
30
rule one31 const MAIL = /^[A-Za-z][A-Za-z0-9]{1,4}@yahoo\.com$/;
32
33 document.getElementById("go").onclick = () => {
34 const mail = document.getElementById("mail").value.trim();
35
36 const okMail = show("eMail",
37 mail === "" ? "Email is required" :
38 !MAIL.test(mail) ? "Start with a letter, 2 to 5 characters, then @yahoo.com" : "");
39
40 show("out", okMail ? "Registered" : "");
41 };
42 </script>
43</body>
44</html>
untitled×
127.0.0.1:5500/index.html
live
try a12@yahoo.com, then 1abc@yahoo.com, then asha@gmail.com
^[A-Za-z] — the very first character must be a letter. That is “must start with an alphabet”.
[A-Za-z0-9]{1,4} — then one to four more, letters or digits. One plus four gives the range 2 to 5 the question asks for.
If your paper means 2 to 5 characters after the first letter, change {1,4} to {2,5} — and state which reading you used.
@yahoo\.com$ — then exactly that text, and $ means nothing may follow.
The backslash before the dot matters. A bare . in a pattern means any character, so yahooXcom would pass. \. means a real full stop.
The question says yahoo.com, so the answer says yahoo.com. Every other example in this course uses gmail, but an exam answer must match the question it was asked. Change the domain in the pattern and the same rule works anywhere.
CHUNK 2 OF 5 0:07 – 0:15

A college address, and a link that sends to it

PYQ · 15259 N · Q12(a) · 4 marks
“Write JavaScript program to validate email id of the format 1602-YY-7YY-YYY@vce.ac.in and send an email to the above mail-id when a link with text is clicked.”
Two halves. Validate the shape — the roll-number pattern from Module 9 with a domain glued on. Then build a link that sends to it. Two marks each.
Add this below the email field in the same file. The <a> is new: its href is rewritten by the script every time the address changes.
10-registration / register.html  — added below the first fieldruns
a second field, and a link1 <label>College email</label>
2 <input id="vce" value="1602-24-733-001@vce.ac.in">
3 <p class="error" id="eVce"></p>
4
5 <a id="mailLink" href="#">Email this address</a>
6
the rule, and what the link becomes7 <script>
8 const VCE = /^1602-[0-9]{2}-7[0-9]{2}-[0-9]{3}@vce\.ac\.in$/;
9
10 const checkVce = () => {
11 const v = document.getElementById("vce").value.trim();
12
13 const ok = show("eVce",
14 v === "" ? "College email is required" :
15 !VCE.test(v) ? "Must look like 1602-24-733-001@vce.ac.in" : "");
16
17 const link = document.getElementById("mailLink");
18 link.href = ok ? "mailto:" + v + "?subject=Registration" : "#";
19 link.innerHTML = ok ? "Email " + v : "Fix the address first";
20
21 return ok;
22 };
23
24 document.getElementById("vce").addEventListener("input", checkVce);
25 checkVce();
26 </script>
untitled×
127.0.0.1:5500/index.html
live
try 1602-24-733-015@vce.ac.in, then 9999-24-133-001@vce.ac.in — the second is refused
1602- and the 7 are fixed in the question, so they are typed exactly; only the Y positions become [0-9]. That gives /^1602-[0-9]{2}-7[0-9]{2}-[0-9]{3}@vce\.ac\.in$/. 1602-24-733-015@vce.ac.in passes. 9999-24-133-001@vce.ac.in is refused — a pattern of four digits, two, three and three would have let it through.
mailto: in an href opens the mail program with the address already filled in. It is not JavaScript sending an email — nothing in a browser can do that. It hands the job to Outlook or Gmail.
?subject= after the address pre-fills the subject line. Optional, but it is the sort of detail that turns three marks into four.
The link is rebuilt on every keystroke, and set back to # when the address is wrong — so a broken address can never be mailed.
Clicking that link inside the frame above will do nothing. The preview runs in a sandbox, and a sandbox is not allowed to launch other programs. On your own machine, opened with Live Server, it opens your mail client properly. Try it there — the code is right, the frame is fenced in.
If an examiner asks how the email is actually sent: it is not. The page builds a mailto: address and the operating system hands it to whatever mail program is installed. Actually sending mail needs a server — which is Unit 4.
CHUNK 3 OF 5 0:15 – 0:24

A date, an age, and a pincode

PYQ · 15267 N/O · Q12(a) · 4 marks
“Write JavaScript program to validate date of birth (DOB) and Pincode. DOB to be specified in the format YYYY-MM-DD and ensure the user is atleast 18 years old else show an appropriate error message. Pincode must be a number with 5 digits exactly and should start with digit ‘5’.”
Three rules, and one of them is not a pattern. The format is a pattern. The pincode is a pattern. The age is arithmetic — no pattern can work out how old somebody is.
10-registration / register.html  — two more fieldsruns
two fields1 <label>Date of birth</label>
2 <input id="dob" value="2005-06-14">
3 <p class="error" id="eDob"></p>
4
5 <label>Pincode</label>
6 <input id="pin" value="50003">
7 <p class="error" id="ePin"></p>
8
two patterns9 <script>
10 const DOB = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/;
11 const PIN = /^5[0-9]{4}$/;
12
the age, worked out properly13 const yearsSince = text => {
14 const born = new Date(text);
15 const today = new Date();
16 let years = today.getFullYear() - born.getFullYear();
17 const m = today.getMonth() - born.getMonth();
18 if (m < 0 || (m === 0 && today.getDate() < born.getDate())) {
19 years = years - 1;
20 }
21 return years;
22 };
23
the two checks24 const checkDob = () => {
25 const v = document.getElementById("dob").value.trim();
26 return show("eDob",
27 v === "" ? "Date of birth is required" :
28 !DOB.test(v) ? "Use the format YYYY-MM-DD" :
29 yearsSince(v) < 18 ? "You must be at least 18" : "");
30 };
31
32 const checkPin = () => {
33 const v = document.getElementById("pin").value.trim();
34 return show("ePin",
35 v === "" ? "Pincode is required" :
36 !PIN.test(v) ? "5 digits, starting with 5" : "");
37 };
38 </script>
untitled×
127.0.0.1:5500/index.html
live
try 2010-01-01, then a pincode of 400031, then 500031
/^5[0-9]{4}$/ reads as: starts with 5, then four more digits. One plus four is five in total. Writing [0-9]{5} and checking the first character separately works too and earns the same marks.
The date format is a pattern; the age is not. /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/ only proves it looks like a date. 9999-99-99 passes it.
new Date(text) turns the text into a real date the browser can do arithmetic with. new Date() with nothing inside means today.
Subtracting years is not enough. Somebody born in December 2008 is not 18 in March 2026, even though 2026 minus 2008 is 18. The month and day check on line 18 handles that — and it is worth a mark.
Rules are tested in order and stop at the first failure. An empty box is told it is required, not that the format is wrong. Ordering the rules from most obvious to most specific is what makes the messages helpful.
Typed
Which message
Why
14-06-2005
“Use the format YYYY-MM-DD”
right date, wrong shape — the pattern fails first
2010-01-01
“You must be at least 18”
shape is fine, so the arithmetic runs
400031
“5 digits, starting with 5”
starts with 4
50003
passes
five digits, starts with 5
500031
“5 digits, starting with 5”
six digits, one too many
In our form
2005-06-14 and 50003
both pass, both error lines stay empty
CHUNK 4 OF 5 0:24 – 0:32

A username with a rule at each end

PYQ · 15252 (S) N · Q16(b) part (i) · 4 marks
“Write JavaScript program to validate username with constraints as it must start with underscore symbol, can have digits, alphabets and must end with an alphabet.”
Three constraints, and they pin down three different places. The start, the middle, and the end. This is the question that shows why ^ and $ are not decoration.
10-registration / register.html  — the username fieldruns
one more field1 <label>Username</label>
2 <input id="user" value="_asha24a">
3 <p class="error" id="eUser"></p>
4
one pattern, three constraints5 <script>
6 const USER = /^_[A-Za-z0-9]*[A-Za-z]$/;
7
8 const checkUser = () => {
9 const v = document.getElementById("user").value.trim();
10 return show("eUser",
11 v === "" ? "Username is required" :
12 !USER.test(v) ? "Start with _, letters and digits, end with a letter" : "");
13 };
14 </script>
untitled×
127.0.0.1:5500/index.html
live
try asha24a, then _asha24, then _a
/^_[A-Za-z0-9]*[A-Za-z]$/ ^_ the first character is an underscore [A-Za-z0-9]* any number of letters and digits, including none [A-Za-z]$ the last is a letter underscore · anything in the middle · a letter at the end — the three constraints, in order
Read a pattern left to right and it reads like the question
* means zero or more, + means one or more. Here * is right: _a is a legal username under the question’s wording, with nothing in the middle at all.
The last letter is matched separately from the middle. That is why the middle can contain digits but the value still cannot end in one.
Try _asha24 and it is rejected. Underscore, correct. Middle, correct. But it ends in a digit, and the question said it must end with an alphabet.
The wrong answer that looks right: /^_[A-Za-z0-9]+[A-Za-z]$/ with a + instead of a *. It rejects _a, because + demands at least one character in the middle before the final letter. The question never said that. One character, one mark.
CHUNK 5 OF 5 0:32 – 0:40

Counting checkboxes — the question asked twice

PYQ · 15252 (S) N · Q16(b) part (ii) · 4 marks
“Checkboxes — User must select atleast two courses. Four checkboxes represent four courses C, Java, Python and Ruby.”
PYQ · 15267 N/O · Q16(b) · 4 marks
“Write a JavaScript program to ensure that user selects atleast four courses. Assume that there are 6 courses for enrollment and is represented by checkboxes.”
The same question with two numbers changed. Four boxes needing two, six boxes needing four. Write it once with the number in a variable and you have answered both — change NEEDED and add two more boxes.
10-registration / courses.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Choose your courses</title>
6 <style>
7 body { font-family: Arial; max-width: 420px; }
8 button { padding: 8px 16px; background: skyblue; }
9 .error { color: red; font-size: 13px; min-height: 16px; }
10 .ok { color: green; }
11 </style>
12</head>
13<body>
four checkboxes, one class between them14 <h3>Choose your courses</h3>
15
16 <label><input type="checkbox" class="course" value="C"> C</label><br>
17 <label><input type="checkbox" class="course" value="Java"> Java</label><br>
18 <label><input type="checkbox" class="course" value="Python"> Python</label><br>
19 <label><input type="checkbox" class="course" value="Ruby"> Ruby</label>
20
21 <p class="error" id="eC"></p>
22 <button id="go">Enrol</button>
23 <p class="ok" id="out"></p>
24
count what is ticked25 <script>
26 const NEEDED = 2;
27
28 document.getElementById("go").onclick = () => {
29 const boxes = document.querySelectorAll(".course");
30 const picked = [...boxes].filter(b => b.checked);
31
32 if (picked.length < NEEDED) {
33 document.getElementById("eC").innerHTML =
34 "Choose at least " + NEEDED + " courses. You picked " + picked.length + ".";
35 document.getElementById("out").innerHTML = "";
36 return;
37 }
38
39 document.getElementById("eC").innerHTML = "";
40 document.getElementById("out").innerHTML =
41 "Enrolled in: " + [...picked].map(b => b.value).join(", ");
42 };
43 </script>
44</body>
45</html>
untitled×
127.0.0.1:5500/index.html
live
tick one box and press Enrol, then tick another
Every checkbox carries class="course". That is the handle for finding them all at once. Ids are for one element; a class is for a group.
querySelectorAll(".course") finds all of them. The dot means “by class”, the same dot you met in the stylesheet in Module 1. Module 11 covers this properly — here, read it as “give me every element with that class”.
b.checked is true or false. Not the value, not the text — only whether it is ticked. Reading .value on an unticked box still gives you its value, which is why counting must use .checked.
[...boxes] turns the result into a real array so filter works on it. querySelectorAll hands back something array-like that does not have every array method. The three dots from Module 5 solve it.
The message says how many they picked. “Choose at least 2. You picked 1.” is a better error than “Choose at least 2”, and costs nothing.
To answer the six-course version: add two more <label> lines and change NEEDED to 4. Nothing else moves. Say that in the exam — showing you noticed the two questions are the same question is worth more than writing it out twice.

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-first-script · 03-variables · 04-functions · 05-objects ├── 06-arrays · 07-strings · 08-events · 09-validation └── 10-registration ├── register.html grown across chunks 1-4 └── courses.html new

Practice

1Change the courses page to the six-course version needing four. Write out only the lines that change.
Show the solution
Two changes, that is all.
const NEEDED = 4;  // was 2

<label><input type="checkbox" class="course" value="C++"> C++</label><br>
<label><input type="checkbox" class="course" value="Go"> Go</label>
The counting code does not move. It never knew how many boxes there were — it asks the page. That is why putting the number in a named constant was worth doing: the rule lives in one place.
2The question asks for exactly 5 digits starting with 5. A student writes /^5[0-9]{5}$/ and the valid value 50003 is rejected. What went wrong?
Show the solution
{5} asks for five more digits after the 5 — six in total. 50003 has only four after the 5, so it fails.

The fix is {4}: /^5[0-9]{4}$/.

How to avoid it: count the characters the pattern demands, out loud, against the number in the question. Off-by-one in a quantifier is the most common pattern mistake there is.
3Which of these rules can a pattern not check, and why? (a) email format  (b) at least 18 years old  (c) pincode starts with 5  (d) two passwords match
Show the solution
(b) and (d).

A pattern describes the shape of one piece of text, nothing more. It cannot do arithmetic, so it cannot work out an age — that needs new Date() and a subtraction. And it cannot compare two values, so a password match needs p1 === p2.

(a) and (c) are shape questions, so patterns handle them perfectly.

The rule of thumb: if the answer depends on anything except the characters in that one box, a pattern cannot do it.
That is all seven validation questions from four years of papers, answered. Between Modules 9 and 10 you have covered every rule they have ever asked for — and the shape is the same one every time. Next: changing the page itself, which is the other half of the marks.
Module 11 · The DOM, Document Object · 42 min
CHUNK 1 OF 5 0:00 – 0:08

The page as something you can rearrange

Covering the syllabus phrase: Document and Window Objects. This is the other big scorer — Q16(b) is a DOM question in every paper.
New folder 11-dom inside FSWD-Unit2 · new files tree.html · find.html · change.html · boxes.html · missing.html · calc.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
Module 0 showed this in one picture: your file is dead text, and the browser builds a tree of objects from it. You have been reaching into that tree since Module 2 with getElementById. Now it gets its name and its full set of tools.
The DOM
The Document Object Model — the live tree of objects the browser builds from your file. Every tag becomes an object you can read and change. Change the tree, and the page redraws.
YOUR FILE <html> <head> <title> <body> <h2 id="head"> <p class="note"> <p class="note"> text on disk · never changes parsed THE DOM, IN MEMORY html head body title h2 p p objects in memory · changeable JS your script edits these objects the browser redraws · the file is never touched
Seven tags on disk · seven objects in memory · only one of them can be changed
11-dom / tree.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>The tree</title>
6</head>
7<body>
8 <h2 id="head">Vasavi</h2>
9 <p class="note">first note</p>
10 <p class="note">second note</p>
11
two edits to the tree12 <script>
13 document.getElementById("head").innerHTML = "Vasavi College";
14
15 document.title = "Changed from JavaScript";
16 </script>
17</body>
18</html>
untitled×
127.0.0.1:5500/index.html
live
the heading changed, and so did the tab name
document is the whole tree. Every DOM instruction starts there. It is handed to you by the browser — you never make one.
Line 13 changes the heading; line 15 changes the tab. Both are objects in the same tree. The tab is not part of the visible page, which is why it lives on document directly rather than inside the body.
Press refresh and both revert. The tree is rebuilt from the file, and the file still says what it always said. This is the single most useful thing to understand about the DOM.
Change the tree, and the page redraws.
That sentence is the whole module.
CHUNK 2 OF 5 0:08 – 0:16

Finding things in the tree, five ways

You know one of these already. The other four exist because sometimes you want a group rather than a single element, and sometimes you want to describe what you are after rather than name it.
11-dom / find.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Five ways to find</title>
5<style>pre{background:#f4f4f4;padding:8px}</style>
6</head>
7<body>
8 <h2 id="head">Vasavi</h2>
9 <p class="note">first note</p>
10 <p class="note">second note</p>
11 <pre id="out"></pre>
12
five ways to reach in13 <script>
14 const byId = document.getElementById("head");
15 const byClass = document.getElementsByClassName("note");
16 const byTag = document.getElementsByTagName("p");
17 const one = document.querySelector(".note");
18 const all = document.querySelectorAll(".note");
19
what each one hands back20 let out = "";
21 out += "byId " + byId.innerHTML + "\n";
22 out += "byClass " + byClass.length + " found\n";
23 out += "byTag " + byTag.length + " found\n";
24 out += "one " + one.innerHTML + "\n";
25 out += "all " + all.length + " found\n";
26 out += "missing " + document.getElementById("nope");
27
28 document.getElementById("out").innerHTML = out;
29 </script>
30</body>
31</html>
untitled×
127.0.0.1:5500/index.html
live
look at the last line — what an element that does not exist gives you
Method
Hands back
Reach for it when
getElementById
one element, or null
you named it with an id
getElementsByClassName
a live collection
older code — you will read it more than write it
getElementsByTagName
a live collection
every paragraph, every input
querySelector
the first match, or null
you want one, described by a CSS selector
querySelectorAll
a fixed list of all matches
use this for groups — Module 10 counted checkboxes with it
In our page
querySelectorAll(".note")
finds 2 — the same 2 as getElementsByClassName
The dot and the hash come from CSS. querySelector(".note") uses a class, querySelector("#head") an id, querySelector("p") a tag. Anything you can write in a stylesheet you can write here — which is why these two replaced the others.
Not finding something gives null, not an error. Line 26 proves it. The error only comes on the next line, when you try to use that nothing — which is the message Module 2 taught you to read.
“Live” means it keeps updating. A collection from getElementsByClassName grows by itself if you add a matching element later. querySelectorAll hands you a snapshot that does not. The snapshot is easier to reason about, which is another reason to prefer it.
A collection is not quite an array. It has .length and you can index it, but not every array method works. [...boxes] turns it into a real one — the three dots again.
Two are enough. getElementById when you named it, querySelectorAll when you want a group. The other three appear in your papers, so recognise them — but you never need to write them.
CHUNK 3 OF 5 0:16 – 0:25

Changing what is already there

Once you hold an element, four things can be changed: what is inside it, what it looks like, which classes it carries, and — for a form field — its value. Press the button and watch all four at once.
11-dom / change.htmlruns
the page and two styles1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Changing things</title>
6 <style>
7 body { font-family: Arial; max-width: 420px; }
8 .highlight { background: #fff3a0; padding: 2px 5px; }
9 button { padding: 6px 12px; background: skyblue; }
10 </style>
11</head>
12<body>
three paragraphs and a box13 <p id="a">plain text</p>
14 <p id="b">plain text</p>
15 <p id="c">plain text</p>
16 <input id="d" value="type here">
17 <button id="go">Change them</button>
18
four kinds of change19 <script>
20 document.getElementById("go").onclick = () => {
21 const a = document.getElementById("a");
22 const b = document.getElementById("b");
23 const c = document.getElementById("c");
24
25 a.innerHTML = "<b>bold</b> from innerHTML";
26 b.textContent = "<b>bold</b> from textContent";
27
28 c.style.color = "green";
29 c.classList.add("highlight");
30 c.innerHTML = "styled two ways";
31
32 document.getElementById("d").value = "set from JavaScript";
33 };
34 </script>
35</body>
36</html>
untitled×
127.0.0.1:5500/index.html
live
look at paragraphs a and b — the same text, two very different results
innerHTMLTags inside the text are obeyed. Paragraph a shows the word bold actually bold.
textContentTags are shown as text. Paragraph b literally displays <b>bold</b>.
What you set
Changes
Note
.innerHTML
the content, tags obeyed
the usual choice — but see the warning
.textContent
the content, tags shown literally
safer whenever the text came from a user
.value
what is in a form field
innerHTML does nothing to an <input>
.style.color
one styling property
fine for one thing, clumsy for several
.classList.add
applies a whole class from your CSS
better — the styling stays in the stylesheet
In our page
paragraph c uses both
green from style, yellow background from the class
The one real danger in this module. Putting something a user typed into innerHTML means any tags they typed are obeyed — including a <script>. Use textContent for anything that came from a person, and innerHTML only for text you wrote yourself. It costs nothing and it is the habit real work depends on.
innerHTML on an input does nothing at all — no error, no change. An <input> has no inside; its text lives in value. If a box refuses to fill from your script, this is almost always why.
classList.add, .remove, .toggle. Three methods, and toggle is the useful one — it adds the class if it is missing and removes it if it is there, which is one line for a show/hide button.
Property names lose their hyphens. CSS says background-color; JavaScript says style.backgroundColor. A hyphen would be read as a minus sign.
CHUNK 4 OF 5 0:25 – 0:34

Making new elements, and taking them away

PYQ · 15279 N/O · Q16(b) · 4 marks
“What is DOM? Write a JavaScript program that creates a new text box each time a button is clicked. The program should allow the user to create a maximum of five text boxes, else an appropriate error message should be displayed.”
Two halves again. Define the DOM in a sentence — the tree of objects the browser builds from the HTML, which JavaScript can change. Then the program: count, refuse or create.
11-dom / boxes.htmlruns
the page and styles1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Add a text box</title>
6 <style>
7 body { font-family: Arial; max-width: 420px; }
8 input { padding: 8px; width: 200px; display: block; margin-bottom: 6px; }
9 button { padding: 8px 16px; background: skyblue; }
10 .error { color: red; font-size: 13px; min-height: 16px; }
11 </style>
12</head>
two buttons and an empty holder13<body>
14 <h3>Add a text box</h3>
15
16 <button id="add">Add box</button>
17 <button id="undo">Remove last</button>
18 <p class="error" id="err"></p>
19 <div id="holder"></div>
20
count, refuse, or create21 <script>
22 const MAX = 5;
23 const holder = document.getElementById("holder");
24 const err = document.getElementById("err");
25
26 document.getElementById("add").onclick = () => {
27 const boxes = holder.querySelectorAll("input");
28
29 if (boxes.length >= MAX) {
30 err.innerHTML = "You cannot add more than " + MAX + " boxes";
31 return;
32 }
33
34 const box = document.createElement("input");
35 box.type = "text";
36 box.placeholder = "box " + (boxes.length + 1);
37
38 holder.appendChild(box);
39 err.innerHTML = "";
and remove the last one40 };
41
42 document.getElementById("undo").onclick = () => {
43 const boxes = holder.querySelectorAll("input");
44 if (boxes.length === 0) { err.innerHTML = "Nothing to remove"; return; }
45 boxes[boxes.length - 1].remove();
46 err.innerHTML = "";
47 };
48 </script>
49</body>
50</html>
untitled×
127.0.0.1:5500/index.html
live
press Add six times — the sixth is refused
createElement("input") exists, but nowhere yet 1 · MAKE IT box.type = "text" still nowhere · still invisible 2 · SET IT UP holder.appendChild(box) now it is in the tree, and visible 3 · ATTACH IT skip step 3 and nothing appears — and nothing complains
Make it · set it up · attach it · the third step is the one people forget
createElement makes an element that is not on the page. It exists in memory, nothing more. You can set it up as much as you like before anyone sees it.
appendChild puts it into the tree, as the last child of whatever you called it on. That is the moment it appears.
The count comes from the page, not a variable. holder.querySelectorAll("input") asks how many are actually there. Keeping a separate counter works until Remove is pressed and the two disagree.
.remove() takes an element out of the tree. Called on the element itself — no need to find its parent first.
The empty <div id="holder"> is deliberate. New boxes need somewhere to go. Appending to document.body would work but would put them after the error message, which looks wrong.

When the holder’s id is misspelt

11-dom / missing.html  — one letter wrongruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Nowhere to attach</title></head>
5<body>
6 <ul id="list"></ul>
7 <p id="err" style="color: red;"></p>
8 <script>
9 window.addEventListener("error", e => {
10 document.getElementById("err").innerHTML = e.message;
11 });
12 </script>
13 <script>
14 const li = document.createElement("li");
15 li.textContent = "Item 1";
16 document.getElementById("lits").appendChild(li);
17 </script>
18</body>
19</html>
untitled×
127.0.0.1:5500/index.html
live
nothing was added, and the red line says why
The item was made, but there was nowhere to put it. getElementById("lits") found nothing and handed back null, and null has no appendChild. Fix the id to list and Item 1 appears. Lines 9 to 13 only copy the console’s message onto the page so you can read it here.
CHUNK 5 OF 5 0:34 – 0:42

A calculator with only one box

PYQ · 15259 N · Q16(b) · 4 marks
“Write JavaScript program to realize a calculator to perform addition on clicking ‘+’ button and subtraction operation on clicking ‘-’ button. Assume only one text box available to enter the input. Generate the result in the same text box.”
“Only one text box” is the whole difficulty. With two boxes this is three lines. With one, the box has to hold the running total and take the next number — so the page has to remember something between clicks.
11-dom / calc.htmlruns
the page and styles1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>One-box calculator</title>
6 <style>
7 body { font-family: Arial; max-width: 420px; }
8 input { padding: 8px; width: 220px; font-size: 16px; }
9 button { padding: 8px 18px; background: skyblue; font-size: 16px; }
10 .error { color: red; font-size: 13px; min-height: 16px; }
11 </style>
12</head>
one box, two buttons13<body>
14 <h3>Calculator</h3>
15
16 <input id="box" value="0">
17 <p class="error" id="err"></p>
18
19 <button id="plus">+</button>
20 <button id="minus">-</button>
what the page remembers21
22 <script>
23 const box = document.getElementById("box");
24 const err = document.getElementById("err");
25
26 let total = 0;
one press27 let pending = null;
28
29 const press = sign => {
30 const typed = box.value.trim();
31
32 if (typed === "" || isNaN(Number(typed))) {
33 err.innerHTML = "Type a number first";
34 return;
35 }
36
37 err.innerHTML = "";
38 const n = Number(typed);
39
40 total = pending === null ? n
41 : pending === "+" ? total + n
42 : total - n;
43
44 pending = sign;
45 box.value = total;
46 };
47
48 document.getElementById("plus").onclick = () => press("+");
49 document.getElementById("minus").onclick = () => press("-");
50 </script>
51</body>
52</html>
untitled×
127.0.0.1:5500/index.html
live
type 7, press +, type 5, press +, type 2, press -
total and pending live outside the handler. Same reason the doorbell count did in Module 8 — declared inside, they would reset to their starting values on every press.
pending holds which button was pressed last time. That is the trick the question is really asking about. When you press +, the page cannot add anything yet — it has one number. It stores the sign and waits.
pending === null means this is the first press. Nothing to add to, so the total becomes the number typed.
box.value = total writes the answer back into the same box — which is what “generate the result in the same text box” means. Then the next number typed replaces it.
isNaN(Number(typed)) catches anything that is not a number. Number("abc") gives NaN, and isNaN asks whether it did. Module 13 explains why NaN needs its own test.
You do
total
pending
type 7, press +
7
"+"
type 5, press +
12
"+"
type 2, press −
14
"−"
type 4, press −
10
"−"
In the frame
the box shows the running total
type over it to continue

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-first-script · 03-variables · 04-functions · 05-objects · 06-arrays ├── 07-strings · 08-events · 09-validation · 10-registration └── 11-dom ├── tree.html new ├── find.html new ├── change.html new ├── boxes.html new ├── missing.html new └── calc.html new

Practice

1A button should add a new list item to a <ul> each time it is pressed, numbered “Item 1”, “Item 2” and so on. Write the handler.
Show the solution
document.getElementById("go").onclick = () => {
  const list = document.getElementById("list");
  const n = list.querySelectorAll("li").length + 1;

  const li = document.createElement("li");
  li.textContent = "Item " + n;
  list.appendChild(li);
};
Same three steps as the text boxes: make it, set it up, attach it. And the count comes from the page again — querySelectorAll("li").length — so removing an item never leaves the numbering wrong.
2A student writes this and nothing appears. What is missing?
const p = document.createElement("p");
p.textContent = "Hello";
Show the solution
Step three. The paragraph was made and filled, but never attached to the tree — so it exists in memory and nowhere else.

Add: document.body.appendChild(p); or append it to a specific holder.

Why no error: creating and filling an element are both perfectly legal on their own. JavaScript has no way to know you meant to show it. This is the same silence as a heading in the head, and as a string method whose result nobody caught.
3When would you use textContent instead of innerHTML, and what is the risk of getting it wrong?
Show the solution
Use textContent for anything a user typed. Use innerHTML only when you wrote the text yourself and it genuinely contains tags you want obeyed.

The risk: innerHTML obeys tags. Put a user’s input through it and whatever tags they typed become part of your page — a <script> among them. The name for this is cross-site scripting, and it is one of the oldest problems on the web.

The habit: if a person typed it, use textContent. It costs nothing and removes the question entirely.
You can now find, change, create and remove anything on a page. With Modules 9 and 10, that is every practical question the papers ask. What is left is the room the page sits in, and the handful of oddities Q4 keeps asking about.
Module 12 · The Window Object · 26 min
CHUNK 1 OF 3 0:00 – 0:08

The room the page sits in

Completing the syllabus phrase Document and Window Objects. Module 11 covered the document; this is the other half.
New folder 12-window inside FSWD-Unit2 · new files room.html · dialogs.html · glance.html · onload.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
The document is the page. The window is the browser tab the page is sitting in — its size, its address, its dialogs, its clock. The page cannot see outside itself, but the window can.
window
The room. Everything the browser gives you lives here, including document itself. It is handed to you already made, and it is the outermost thing you can reach.
window the browser tab document everything on the page headings, forms, buttons Module 11 alert · confirm prompt dialogs setTimeout setInterval the clock innerWidth innerHeight the size location open the address the document is inside the window — so window.document and document are the same thing
One room, and the page is one of the things in it
12-window / room.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>The room</title>
5<style>pre{background:#f4f4f4;padding:8px}</style></head>
6<body>
7 <pre id="out"></pre>
8
is it really the same object?9 <script>
10 let out = "";
11
12 out += "same thing? " + (window.document === document) + "\n";
13 out += "alert is window? " + (window.alert === alert) + "\n\n";
14
what the room knows15 out += "window width " + window.innerWidth + "\n";
16 out += "window height " + window.innerHeight + "\n";
17 out += "page address " + window.location.href + "\n\n";
18
19 const greeting = "hello";
20 out += "my variable " + greeting;
21
22 document.getElementById("out").innerHTML = out;
23 </script>
24</body>
25</html>
untitled×
127.0.0.1:5500/index.html
live
both comparisons say true
window.document === document is true. They are one object with two names. Everything on window can be written without the window. in front — which is why you have never had to type it.
So alert(...) is really window.alert(...). Same for setTimeout, location, and every dialog in the next chunk.
innerWidth and innerHeight are the visible area in pixels. Resize the browser and they change. This is how a page reacts to a phone without CSS.
location.href is the address bar. Read it to see where you are; assign to it and the browser navigates. It is the one property that does something when you set it.
The exam sentence: window is the top-level object representing the browser tab; document is the page inside it, and is a property of window. One line, and it answers “differentiate between window and document” completely.
CHUNK 2 OF 3 0:08 – 0:18

Three dialogs, and a clock

The window can interrupt the user three ways and can run something later. All four appear in the papers, and all four are one line each.
alert
Shows a message. Hands back nothing. The page freezes until it is dismissed.
confirm
Asks a yes-or-no question. Hands back true or false.
prompt
Asks for text. Hands back what they typed, or null if they cancelled.
setInterval
Runs something over and over, every so many milliseconds. setTimeout is the same but runs once.
12-window / dialogs.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Dialogs and timers</title>
6 <style>
7 body { font-family: Arial; max-width: 420px; }
8 button { padding: 8px 14px; background: skyblue; margin: 0 6px 6px 0; }
9 </style>
10</head>
11<body>
12 <h3>Three dialogs, one clock</h3>
five buttons13
14 <button id="a">alert</button>
15 <button id="b">confirm</button>
16 <button id="c">prompt</button>
17 <button id="d">start clock</button>
18 <button id="e">stop clock</button>
19
20 <p id="out">nothing yet</p>
21
the three dialogs22 <script>
23 const out = document.getElementById("out");
24
25 document.getElementById("a").onclick = () => {
26 alert("Saved.");
27 out.innerHTML = "the alert was dismissed";
28 };
29
30 document.getElementById("b").onclick = () => {
31 const yes = confirm("Delete this record?");
32 out.innerHTML = yes ? "they said yes" : "they said no";
33 };
34
35 document.getElementById("c").onclick = () => {
36 const name = prompt("Your name?", "Asha");
37 out.innerHTML = name === null ? "they cancelled" : "hello " + name;
the clock38 };
39
40 let ticker = null;
41 let count = 0;
42
43 document.getElementById("d").onclick = () => {
44 if (ticker !== null) return;
45 ticker = setInterval(() => {
46 count = count + 1;
47 out.innerHTML = "tick " + count;
48 }, 1000);
49 };
50
51 document.getElementById("e").onclick = () => {
52 clearInterval(ticker);
53 ticker = null;
54 out.innerHTML = "stopped at " + count;
55 };
56 </script>
57</body>
58</html>
untitled×
127.0.0.1:5500/index.html
live
press each button — the dialogs are real, and the clock really ticks
All three dialogs stop everything. Nothing else on the page runs, no animation moves, until the user clicks. That is why real sites avoid them — but it is exactly why they are handy to teach with.
prompt can give you three different things: the text they typed, an empty string if they pressed OK with an empty box, or null if they cancelled. Checking only for empty misses the cancel.
The second argument to prompt pre-fills the box. prompt("Your name?", "Asha") — small, and it makes a demo much smoother.
setInterval hands back a ticket. Line 40 keeps it in ticker. Without that ticket you cannot ever stop it — clearInterval needs it.
Line 39 stops a second clock starting. Press Start twice without it and two intervals run at once, the number jumps by two, and only one can be stopped. This is the classic timer bug.
Milliseconds, not seconds. setInterval(fn, 1000) is once a second. Write 1 instead of 1000 and it runs a thousand times a second, which will freeze the tab. If your page locks up after adding a timer, check that number first.
Call
Hands back
Test it with
alert(msg)
undefined
nothing — there is nothing to test
confirm(msg)
true / false
if (yes) { ... }
prompt(msg, start)
text, or null
if (name === null) for cancel
setTimeout(fn, ms)
a ticket
clearTimeout(ticket)
setInterval(fn, ms)
a ticket
clearInterval(ticket)
In our page
press confirm and choose Cancel
the paragraph reads “they said no”

The window at a glance

Property or method
What it does
Example → what you see
location.href
the address bar — read it, or set it to go somewhere
location.href"http://127.0.0.1:5500/glance.html"
location.reload()
loads the page again
a Refresh button → the page starts from scratch
history.back()
the browser’s Back button
a Back link → the previous page
navigator.language
facts about the browser; navigator.userAgent gives its name and version
navigator.language"en-IN"
screen.width
the whole monitor, in pixels
screen.width1366
window.innerWidth
the visible part of the tab
changes as you resize the window
window.open() / close()
opens a new tab; closes one the script opened
open("result.html") → a new tab. The frames on this page are not allowed to open one; Live Server is.
scrollTo(0, 0)
jumps to a spot on the page
a Back-to-top button → the top of the page
In our page
four of these, printed below
the frame reports its own values
12-window / glance.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Window at a glance</title></head>
5<body>
6 <pre id="out"></pre>
7
8 <script>
9 let out = "";
10 out += "location.href " + location.href + "\n";
11 out += "navigator.language " + navigator.language + "\n";
12 out += "screen.width " + screen.width + "\n";
13 out += "innerWidth " + innerWidth;
14
15 document.getElementById("out").innerHTML = out;
16 console.log(out);
17 </script>
18</body>
19</html>
untitled×
127.0.0.1:5500/index.html
live
the frame reports its own values — yours will differ
Every name on the left belongs to window. location.href is short for window.location.href, the same way alert was.
The frame prints about:srcdoc, not an address. The preview has no address of its own. Open the file with Live Server and the same line prints http://127.0.0.1:5500/....
Line 16 sends the same text to the console, so your own copy shows it in both places.
Model answer · window object
“Explain the window object with its properties and methods.”
What it is: window is the top-level object for the browser tab; document, the dialogs and the timers all belong to it.
Properties: location (the address), history, navigator (the browser), screen, innerWidth and innerHeight.
Methods: alert, confirm, prompt, setTimeout, setInterval, open, close, scrollTo.
Finish with code: alert(location.href); shows the address; setTimeout(() => alert("hi"), 1000); says hi after one second.
CHUNK 3 OF 3 0:18 – 0:26

The rescue for a script in the wrong place

Module 2 opened with a script in the head that could not find its element, and the fix was to move the script to the bottom. There is a second fix, and it is the only reason you would ever leave a script in the head.
12-window / onload.htmlruns
the head1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Load order</title>
6
wait, then run7 <script>
8 window.onload = () => {
9 document.getElementById("box").innerHTML = "the rescue worked";
10 };
11 </script>
12
13</head>
the body, built afterwards14<body>
15 <p id="box">waiting...</p>
16</body>
17</html>
untitled×
127.0.0.1:5500/index.html
live
the script is in the head, and it works anyway
SCRIPT IN THE HEAD, NO onload script runs looks for #box — not there null body built too late — the script has already given up SCRIPT IN THE HEAD, WITH onload handler installed body built load fires now it runs the instructions waited — same script, right moment
Two orders · the second one waits for the page to exist
window.onload is an event handler, exactly like the button handlers in Module 8. It installs instantly and runs later — when the page has finished building.
So the script does not move; the timing moves. The code still sits in the head, but the part that touches the page now waits.
Prefer the script at the bottom anyway. It is simpler, it needs no extra layer, and it runs slightly sooner. Use onload when you cannot move the script — which in this unit is almost never.
Script at the bottomSimpler. Runs as soon as the body exists. What this course uses.
Script in the head + onloadWaits for everything, images included. Useful when the script must load first — and it is what older papers show.

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-first-script · 03-variables · 04-functions · 05-objects · 06-arrays ├── 07-strings · 08-events · 09-validation · 10-registration · 11-dom └── 12-window ├── room.html new ├── dialogs.html new ├── glance.html new └── onload.html new

Practice

1Differentiate between the window object and the document object, with one example of something each can do that the other cannot.
Show the solution
window is the browser tab; document is the page inside it. document is a property of window, which is why window.document === document.

Only window can: tell you the tab size with innerWidth, read or change the address with location, show a dialog, or set a timer.

Only document can: find and change elements — getElementById, createElement, innerHTML.

The one-line answer: window represents the browser environment; document represents the content loaded into it.
2A page has a Start button that runs setInterval. A user presses it four times. What happens, and how do you prevent it?
Show the solution
Four separate clocks run at once. The counter jumps by four each second, and clearInterval only stops the last one because each earlier ticket was overwritten. The other three keep running with no way to reach them.

The fix is the guard on line 39 of our page:
if (ticker !== null) return;
Or clear any existing one before starting: clearInterval(ticker); as the first line of the handler. Either works; the guard is clearer about the intent.
3What is the difference between these three, and when does each matter?
const a = prompt("Name?");  // user presses Cancel
const b = prompt("Name?");  // user presses OK with an empty box
const c = prompt("Name?");  // user types Asha
Show the solution
a is null — they refused. b is "" — an empty string; they agreed but gave nothing. c is "Asha".

Why it matters: if (!name) treats a and b the same, which is often what you want. But if you need to tell “cancelled” apart from “left it blank” — and a real form usually does — you must test name === null separately.

Connects to Module 13: both null and "" are falsy, which is exactly why !name cannot tell them apart.
Both halves of “Document and Window Objects” are now covered. Next: the handful of oddities that Q4 has asked about in every paper — and the reason they exist traces straight back to Module 0.
Module 13 · Quirks, Coercion and Legacy JavaScript · 32 min
CHUNK 1 OF 4 0:00 – 0:08

The things that look wrong, and why

This module exists for one reason: Q4 is a “predict the output” question in every single paper, and every time it has been one of these. Four marks over two papers, from four small oddities.
New folder 13-quirks inside FSWD-Unit2 · new files falsy.html · equals.html · hoist.html · with.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
Module 0 said to hold on to the ten days. Here is where that pays. Everything in this module traces back to a decision made in a hurry in 1995, kept because the whole web already depended on it.
Truthy
A value that behaves like true when JavaScript needs a yes or no — inside an if, for instance. Almost everything is truthy.
Falsy
The six values that behave like false. Learning these six is easier than learning the infinite list of truthy ones.
13-quirks / falsy.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Truthy and falsy</title>
5<style>pre{background:#f4f4f4;padding:8px}</style></head>
6<body>
7 <pre id="out"></pre>
8
twelve values worth testing9 <script>
10 const values = [false, 0, "", null, undefined, NaN,
11 "0", "false", [], {}, -1, " "];
12
a label for printing13 const label = v =>
14 Array.isArray(v) ? "[]" :
15 v !== null && typeof v === "object" ? "{}" :
16 typeof v === "string" ? JSON.stringify(v) : String(v);
17
ask each one18 let out = "";
19 values.forEach(v => {
20 out += (v ? " truthy " : " falsy ") + label(v) + "\n";
21 });
22
23 document.getElementById("out").innerHTML = out;
24 </script>
25</body>
26</html>
untitled×
127.0.0.1:5500/index.html
live
twelve values — six are falsy and the rest surprise people
THE SIX FALSY VALUES · MEMORISE THESE false 0 "" null undefined NaN THE LOOKALIKES · ALL TRUTHY "0" "false" [] {} -1 " " a space
Six falsy values · everything else is truthy, including things that look empty
"0" is truthy. It is a string with a character in it. Only the number zero is falsy.
[] and {} are truthy. An empty list is still a list. To ask whether it has anything in it, use .length.
A single space is truthy. " " is not "". This is exactly why every validation in Modules 9 and 10 calls .trim() before testing.
NaN means “not a number” and comes from arithmetic that failed — Number("abc"), for instance. It is the only falsy value that is technically of type number.
Six values are falsy. Everything else is truthy.
Including an empty list, an empty object, and a single space.
CHUNK 2 OF 4 0:08 – 0:17

Two equals signs, or three

You have written === throughout this course without being told why the third character is there. Here it is: == converts before comparing, and the conversions are not what anyone would guess.
==  looseDifferent types? Convert one and try again. Almost always the wrong tool.
===  strictDifferent types means not equal, full stop. No conversion. Use this always.
13-quirks / equals.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Two equals or three</title>
5<style>pre{background:#f4f4f4;padding:8px}</style></head>
6<body>
7 <pre id="out"></pre>
8
a tidy printer9 <script>
10 let out = "";
11
12 const row = (label, loose, strict) => {
13 out += label.padEnd(18) + String(loose).padEnd(8) +
14 String(strict) + "\n";
15 };
16
six comparisons, both ways17 row("1 == 1 as text", 1 == "1", 1 === "1");
18 row("0 == false", 0 == false, 0 === false);
19 row("empty == false", "" == false, "" === false);
20 row("null == undef", null == undefined, null === undefined);
21 row("[] == false", [] == false, [] === false);
22 row("NaN == NaN", NaN == NaN, NaN === NaN);
23
24 out += "\nand the exam question:\n";
the exam question itself25
26 function A(arg) {
27 if (arg) out += " true " + (arg === true);
28 else out += " false " + (arg === false);
29 }
30
31 A([]);
32
33 document.getElementById("out").innerHTML = out;
34 </script>
35</body>
36</html>
untitled×
127.0.0.1:5500/index.html
live
middle column is ==, right column is ===
PYQ · 15259 N · Q4 · 2 marks
“function A(arg) { if (arg) console.log(“true”, arg === true); else console.log(“false”, arg === false); } What will be the output if A([]); is called?”
The output is true false.

Two steps, one mark each. First: if ([]) — an empty array is truthy, so the if branch runs and the word printed is "true". Second: [] === true — an object against a boolean, different types, so false.

The trap: the same value is treated as true by the if and as not-equal-to-true by ===. Both are correct, and noticing that is the question.
A([]) if ([]) truthy → take this branch prints the word "true" first half of the answer [] === true object against boolean → no prints false second half of the answer true false the answer
The same empty array, judged two different ways two lines apart
Comparison
with ==
with ===
1 and "1"
true — the text becomes a number
false — different types
0 and false
true — false becomes 0
false
"" and false
true — both become 0
false
null and undefined
true — a special rule, no conversion
false
[] and false
true — the array becomes "", then 0
false
NaN and NaN
false — not even equal to itself
false
In our page
five of six are true
every one is false
NaN is not equal to itself. Not with two equals, not with three. It is the one value for which x === x is false. That is why Module 11's calculator used isNaN(...) — there is nothing you could usefully compare it against.
CHUNK 3 OF 4 0:17 – 0:25

Using something before you wrote it

Module 3 said var is broken and pointed here. This is the second half of why. Before your code runs, the browser reads the whole file and files some things away in advance — and what it files, and how, differs by keyword.
13-quirks / hoist.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Hoisting</title>
5<style>pre{background:#f4f4f4;padding:8px}</style></head>
6<body>
7 <pre id="out"></pre>
8
var, read too early9 <script>
10 let out = "";
11
12 out += "before var: " + early + "\n";
13 var early = "I was declared later";
14 out += "after var: " + early + "\n\n";
15
a declaration, called too early16 out += declared() + "\n";
17
18 function declared() { return "a declaration works from anywhere"; }
19
and let, which refuses20 try {
21 out += later;
22 } catch (e) {
23 out += "\nlet: " + e.name + " - cannot use it before its line";
24 }
25
26 let later = "too late";
27
28 document.getElementById("out").innerHTML = out;
29 </script>
30</body>
31</html>
untitled×
127.0.0.1:5500/index.html
live
line 12 reads a variable declared on line 13
WHAT THE BROWSER DOES BEFORE RUNNING A LINE OF YOUR CODE var early the name exists early, holding undefined reading it gives you nothing, and no warning at all function declared() the whole function is filed away, ready calling it early works, and this one is genuinely useful let later the name is reserved, but locked until its line reading it early throws, which is what you want var fails quietly · let fails loudly · a loud failure is the better one
Three declarations, three different answers to “can I use this yet?”
The name for this is hoisting. The browser gathers declarations before running anything, as if they had been lifted to the top of their block.
var hoists the name but not the value. So line 12 finds early, sees undefined, and prints it. No error. A typo can look exactly like this.
A function declaration hoists completely. Which is why Module 4 said only the declaration form can be called from a line above where it is written.
let and const hoist the name but keep it locked until execution reaches their line. Touching it before that throws a ReferenceError. The gap has a name — the temporal dead zone — and it exists so mistakes are noisy.
var gives you undefined and says nothing.
let stops you. That is the whole improvement.
CHUNK 4 OF 4 0:25 – 0:32

The one that was banned, and four more

PYQ · 15267 N/O · Q4 · 2 marks
“What is the output of the following code? var x=5, y=1; var obj = { x:10 }; with(obj) { alert(y) }”
The answer is 1.

with (obj) tells JavaScript: inside this block, look in obj first for any name you meet. obj has an x, so x inside the block means 10. But obj has no y — so the search moves outward and finds the ordinary y, which is 1.

The trap is the x. The question shows you x being shadowed to make you expect something clever from y. Nothing clever happens to y at all.
13-quirks / with.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>with, and other oddities</title>
5<style>pre{background:#f4f4f4;padding:8px}</style></head>
6<body>
7 <pre id="out"></pre>
8
the exam question, run for real9 <script>
10 let out = "";
11
12 var x = 5, y = 1;
13 var obj = { x: 10 };
14
15 with (obj) {
16 out += "inside with, x is " + x + "\n";
17 out += "inside with, y is " + y + "\n";
18 }
19
four things worth knowing20 out += "outside, x is " + x + "\n\n";
21
22 out += "typeof null " + typeof null + "\n";
23 out += "typeof [] " + typeof [] + "\n";
24 out += "typeof NaN " + typeof NaN + "\n";
25 out += "0.1 + 0.2 " + (0.1 + 0.2) + "\n";
26 out += "typeof function " + typeof (() => 1);
27
28 document.getElementById("out").innerHTML = out;
29 </script>
30</body>
31</html>
untitled×
127.0.0.1:5500/index.html
live
the exam question, then four more oddities
OUTSIDE x = 5   y = 1 obj x = 10 no y here x inside → 10 found in obj y inside → 1 not in obj, so found outside you cannot tell by reading which x or y a line means — which is exactly why with was banned
Look in the object first, then outside · the answer is 1
with is forbidden in strict mode, and has been discouraged for twenty years. Adding "use strict"; to the top of a file makes this exact program refuse to run. Never write it. Know it only because your paper asks about it — which it did, in December 2024.
Oddity
What you get
Why
typeof null
"object"
a bug from 1995, never fixable — too much code depends on it
typeof []
"object"
an array is a kind of object — use Array.isArray() instead
typeof NaN
"number"
it is a number-shaped result of failed arithmetic
0.1 + 0.2
0.30000000000000004
not a JavaScript flaw — every language storing decimals in binary does this
typeof (() => 1)
"function"
functions are objects too, but typeof gives them their own label: "function"
In our page
all five printed
none of them are mistakes in your code

Your project so far

FSWD-Unit2 ├── 01-skeleton · 02-first-script · 03-variables · 04-functions · 05-objects · 06-arrays ├── 07-strings · 08-events · 09-validation · 10-registration · 11-dom · 12-window └── 13-quirks ├── falsy.html new ├── equals.html new ├── hoist.html new └── with.html new

Practice

1What does each print?
if ("0")  console.log("A");
if (0 == "")  console.log("B");
if ([] == false)  console.log("C");
if ([] === false)  console.log("D");
Show the solution
A, B and C print. D does not.

A"0" is a string with a character in it, so truthy.
B== turns both into 0.
C — the array becomes "", then 0; false becomes 0.
D=== compares types first, and an object is not a boolean.

The pattern: every surprise here comes from ==. Use === and none of them happen.
2Why does this print undefined rather than throwing, and what would let have done?
console.log(total);
var total = 100;
Show the solution
var hoists the name but not the value. Before the code runs, the browser files away “there is a variable called total” and gives it undefined. Line 1 finds it and prints that.

With let it throwsReferenceError: Cannot access 'total' before initialization. The name is reserved but locked until its own line.

Which is better? The error. A misspelled variable name under var looks exactly like this and gives you undefined with no clue where it came from.
3A student writes if (score = 0) and their code always takes that branch. Two things are wrong — name both.
Show the solution
One — a single = assigns, it does not compare. That line sets score to 0 and then asks whether 0 is truthy.

Two — 0 is falsy, so the branch is actually never taken, not always. Their diagnosis is wrong too, which usually means they are looking at the wrong line.

The fix: if (score === 0). And this is a good argument for const wherever possible — assigning to a const by accident throws immediately.
Both Q4 questions from your papers are now answered, and every oddity you met traces back to the ten days in Module 0. Two modules left: one to pull it all together, one to test yourself against.
Module 14 · ES6 Bridge and Unit Recap · 26 min
CHUNK 1 OF 3 0:00 – 0:10

Three things you will meet again

Classes, modules and promises are introduced here so Units 3–4 (React and Node) are not a cold start — twenty minutes now saves a difficult first week later.
New folder 14-bridge inside FSWD-Unit2 · new files classes.html · promise.html · Ctrl+N then Ctrl+S, name it with .html · right-click → Open with Live Server
Three ES6 features sit at the edge of your syllabus, and all three are unavoidable the moment you open React or Node. Here is each one, running, with a marker for where you will meet it.

Classes — a template for making objects

class
A cutter for stamping out objects that all have the same shape. Module 5 made one student drawer by hand; a class makes as many as you like, each already knowing how to do its own work.
14-bridge / classes.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Classes</title>
5<style>pre{background:#f4f4f4;padding:8px}</style></head>
6<body>
7 <pre id="out"></pre>
8
the template9 <script>
10 class Student {
11 constructor(name, marks) {
12 this.name = name;
13 this.marks = marks;
14 }
15
16 average() {
17 return this.marks.reduce((a, b) => a + b, 0) / this.marks.length;
18 }
19
20 report() {
21 return this.name + " scored " + this.average().toFixed(1);
22 }
23 }
24
two objects from it25 const asha = new Student("Asha", [74, 81, 66]);
26 const ravi = new Student("Ravi", [90, 88, 95]);
27
28 document.getElementById("out").innerHTML =
29 asha.report() + "\n" + ravi.report();
30 </script>
31</body>
32</html>
untitled×
127.0.0.1:5500/index.html
live
two students from one template
constructor runs once, when you say new. Its job is to fill in what makes this object different from the others.
this means “the object being built right now”. Inside asha.report(), this.name is Asha. Inside ravi.report(), the same line gives Ravi.
The methods are written once, shared by every object. That is the saving over Module 5, where each drawer carried its own copy of every function.
You will meet this in Unit 3. React components were written as classes for years, and plenty of code you will read still is.

Modules — splitting code across files

export / import
One file says what it is willing to share; another says what it wants to borrow. Everything else in each file stays private to it.
marks.js export const average = m => ...; const helper = ...; stays private shared app.js import { average } from "./marks.js"; average([74, 81, 66]); every React component you write in Unit 3 begins with a line like this
One file shares · another borrows · the rest stays private
This one fails if you double-click the file, and the error is confusing. Modules only work when the page is served over http://, and the tag must be <script type="module">. Open the file directly and you get “Cross origin requests are only supported for protocol schemes: http…” — which sounds like a security problem and is really the wrong way of opening it. Use Live Server and it works. There is no live frame here for the same reason: the preview is not served from a real address.

Promises — code that waits

A promise
A receipt for something that has not arrived yet. You get the receipt immediately; the value comes later. await means “hold here until it does”.
14-bridge / promise.htmlruns
the page1<!DOCTYPE html>
2<html lang="en">
3<head><meta charset="utf-8">
4<title>Waiting for something</title>
5<style>pre{background:#f4f4f4;padding:8px}</style></head>
6<body>
7 <pre id="out">asking...</pre>
8
something slow, pretended9 <script>
10 const out = document.getElementById("out");
11
12 const fetchMarks = () =>
13 new Promise(done => {
14 setTimeout(() => done([74, 81, 66]), 1500);
15 });
16
waiting for it17 const show = async () => {
18 out.innerHTML = "asking the server...";
19 const marks = await fetchMarks();
20 out.innerHTML = "arrived after 1.5s: " + marks;
21 };
22
23 show();
24
25 console.log("this line ran first, without waiting");
26 </script>
27</body>
28</html>
untitled×
127.0.0.1:5500/index.html
live
wait a second and a half — the text changes on its own
setTimeout here is standing in for a real server. Asking a server for data takes time; this pretends to take 1.5 seconds so you can see the waiting.
await pauses that function only. The rest of the page keeps working — buttons still respond, nothing freezes. That is the whole difference from alert, which stops everything.
async is required before you may write await. One marks the function as one that waits; the other does the waiting.
Line 24 proves it did not block. Open the console — that message appears immediately, long before the marks arrive.
You will meet this in Unit 4. Every request to a database or an API is a promise. It is the single most useful thing on this page.
CHUNK 2 OF 3 0:10 – 0:19

The whole syllabus, one card each

Eight phrases in the syllabus, eight cards. Each carries the definition, where it was taught, and a complete program you can run — not a fragment. This is the page to open the night before.
1Introduction to JavaScript ES6Module 0, 3, 4
JavaScript runs inside the browser and makes a page react without reloading. ES6 (2015) is the version the syllabus names — it added let, const, arrow functions, template strings and classes.
recap / card1.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>ES6</title></head>
3<body>
4 <pre id="out"></pre>
5 <script>
6 const name = "Vasavi";
7 const year = 2026;
8
9 const line = (a, b) => `${a} in ${b}`;
10
11 document.getElementById("out").innerHTML = line(name, year);
12 </script>
13</body></html>
untitled×
127.0.0.1:5500/index.html
live
const, arrow, template string — three ES6 features in one line
2VariablesModule 3
const for a value that will not be reassigned, let when it will. Never var — it leaks out of its block and hoists as undefined.
recap / card2.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>Variables</title></head>
3<body>
4 <pre id="out"></pre>
5 <script>
6 const price = 60;
7 let qty = 3;
8
9 qty = qty + 1;
10
11 document.getElementById("out").innerHTML =
12 `${qty} at ${price} = ${qty * price}`;
13 </script>
14</body></html>
untitled×
127.0.0.1:5500/index.html
live
const stays, let changes
3ObjectsModule 5
A labelled drawer. Related facts about one thing, each behind a name. Read with a dot; const stops reassignment, not modification.
recap / card3.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>Objects</title></head>
3<body>
4 <pre id="out"></pre>
5 <script>
6 const student = {
7 name: "Asha",
8 roll: "733-001",
9 marks: [74, 81, 66]
10 };
11
12 student.roll = "733-002";
13
14 document.getElementById("out").innerHTML =
15 student.name + " " + student.roll + " " + student.marks;
16 </script>
17</body></html>
untitled×
127.0.0.1:5500/index.html
live
one drawer, three compartments, one changed
4ArraysModule 6
A numbered shelf, counted from 0. push and pop at the end; map makes a new list, filter a shorter one, reduce a single value. sort() alone compares as text.
recap / card4.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>Arrays</title></head>
3<body>
4 <pre id="out"></pre>
5 <script>
6 const marks = [74, 81, 66, 45];
7
8 const passed = marks.filter(m => m >= 50);
9 const total = marks.reduce((a, b) => a + b, 0);
10 const sorted = [...marks].sort((a, b) => a - b);
11
12 document.getElementById("out").innerHTML =
13 `passed ${passed}\ntotal ${total}\nsorted ${sorted}`;
14 </script>
15</body></html>
untitled×
127.0.0.1:5500/index.html
live
filter, reduce, and sort with a comparator
5String ManipulationModule 7
A row of characters, numbered from 0, that cannot be edited in place. Every method hands back a new string. trim() first, always.
recap / card5.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>Strings</title></head>
3<body>
4 <pre id="out"></pre>
5 <script>
6 const raw = " Dr. Asha Reddy ";
7 const s = raw.trim();
8
9 document.getElementById("out").innerHTML =
10 s.toUpperCase() + "\n" +
11 s.split(" ")[0] + "\n" +
12 s.includes("Reddy");
13 </script>
14</body></html>
untitled×
127.0.0.1:5500/index.html
live
trim, then work on the clean copy
6Scripting FunctionsModule 4
A recipe you can run again. Four ways to write one; the arrow form is shortest. Only a declaration may be called from a line above where it is written.
recap / card6.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>Functions</title></head>
3<body>
4 <pre id="out"></pre>
5 <script>
6 function area(w, h) { return w * h; }
7
8 const fare = km => km * 12;
9
10 document.getElementById("out").innerHTML =
11 area(4, 5) + " and " + fare(7);
12 </script>
13</body></html>
untitled×
127.0.0.1:5500/index.html
live
a declaration and an arrow, side by side
7Event HandlingModule 8
A doorbell you install and forget. addEventListener stacks; onclick = replaces. On a form, event.preventDefault() stops the page reloading.
recap / card7.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>Events</title>
3<style>button{padding:6px 12px;background:skyblue}</style></head>
4<body>
5 <button id="go">Press me</button>
6 <p id="out">not yet</p>
7 <script>
8 let n = 0;
9
10 document.getElementById("go").addEventListener("click", () => {
11 n = n + 1;
12 document.getElementById("out").innerHTML = "pressed " + n;
13 });
14 </script>
15</body></html>
untitled×
127.0.0.1:5500/index.html
live
press it — the count is remembered
8Document and Window ObjectsModule 11, 12
document is the page; window is the tab it sits in. Find with getElementById or querySelectorAll; change with innerHTML, textContent, value, classList. Create with createElement then appendChild.
recap / card8.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>DOM</title></head>
3<body>
4 <ul id="list"></ul>
5 <pre id="out"></pre>
6 <script>
7 const list = document.getElementById("list");
8
9 ["C", "Java", "Python"].forEach(name => {
10 const li = document.createElement("li");
11 li.textContent = name;
12 list.appendChild(li);
13 });
14
15 document.getElementById("out").innerHTML =
16 list.querySelectorAll("li").length + " items · window is " +
17 (window.document === document ? "the room" : "?");
18 </script>
19</body></html>
untitled×
127.0.0.1:5500/index.html
live
three items created, then counted
Read each card top to bottom: the syllabus phrase, the definition in one or two sentences, then a program that runs. If the definition makes sense and the program does not surprise you, that phrase is covered.
Every program here is complete. Not a fragment, not a snippet with the boilerplate implied — you could type any one of these into a new file and it would work. That is deliberate: fragments look finished and then fail when you try them.
The Module badge on each card is the way back. If a card does not click, that number is where the slow version lives with the diagrams and the failures.
Cards 1 to 6 are the language; 7 and 8 are the browser. The first six would work anywhere JavaScript runs, including Node in Unit 4. The last two only work in a browser, because only a browser has a page and a window.
Notice what is not here. No validation card, no regular expressions — those are not syllabus phrases, they are what the syllabus phrases are used for. Modules 9 and 10 hold them.

ES6 in one card

Feature
One line
Taught in
let / const
const price = 60; let qty = 3;
arrow functions
const square = n => n * n;
template literals
`${qty} dosas`
default parameters
(amount, rate = 0.05) => amount * rate
rest / spread
(...marks) => marks.length   [...nums]
destructuring
const { name, city } = student;
classes
class Student { constructor(name) { this.name = name; } }
modules
export const fee = 60;   import { fee } from "./fee.js";
In our course
every row appears in a file you built
press a badge to go back to it
Eight cards, eight runnable programs.
If you can write these from memory, the unit is covered.
CHUNK 3 OF 3 0:19 – 0:26

Everything you built, and where it leads

Fourteen folders, forty-five files, every one of them a page that runs. If your folder looks like this, you have done the work.
FSWD-Unit2 ├── 01-skeleton index.html · order.html ├── 02-first-script hello.html · four.html · typo.html · click.html ├── 03-variables box.html · types.html · leak.html · join.html · total.html ├── 04-functions greet.html · four.html · arrows.html · this.html · fare.html ├── 05-objects student.html · edit.html · record.html · average.html ├── 06-arrays shelf.html · change.html · sort.html · typo.html · walk.html · filter.html ├── 07-strings row.html · methods.html · compare.html · names.html · shout.html ├── 08-events bell.html · three.html · typo.html · watch.html · form.html · target.html ├── 09-validation blank.html · rules.html · password.html · fullname.html · pattern.html ├── 10-registration register.html · courses.html ├── 11-dom tree.html · find.html · change.html · boxes.html · missing.html · calc.html ├── 12-window room.html · dialogs.html · glance.html · onload.html ├── 13-quirks falsy.html · equals.html · hoist.html · with.html └── 14-bridge classes.html · promise.html

Where this JavaScript goes next

JS React the page you build UNIT 3 FRONT END JS Express answering requests UNIT 4 JS Node running on the server UNIT 4 BACK END JS Mongo queries are objects UNIT 5 one language, all four boxes the objects, arrays, functions and arrow syntax from this unit are the same in every one
This unit is not a topic on its own · it is the language the next three units are written in

The habits, in one place

Habit
Why
First met
const by default, let when reassigned
var leaks and hoists as undefined
Module 3
===, never ==
loose equality converts, and the conversions surprise you
Module 13
.trim() before testing anything typed
a space is truthy and invisible
Module 7
Number(...) before comparing
a text box hands back text, and "9" < "17" is false
Module 9
script at the bottom of the body
the elements have to exist before you reach for them
Module 2
check every field, then decide
otherwise the user finds their mistakes one at a time
Module 9
clear the error before showing a result
a fixed mistake keeps its red message forever
Module 7
textContent for anything a person typed
innerHTML obeys tags they may have typed
Module 11
All eight
appear in the worked answers throughout
and in the marking

Practice — check yourself before the self-test

1Without looking back: name the six falsy values, and say which of [], "0" and " " are truthy.
Show the solution
The six: false, 0, "", null, undefined, NaN.

All three of the others are truthy. [] is an object, "0" is a string with a character in it, and " " is a string with a space in it.

Why it earns marks: Q4 has been a truthiness question in two of your four papers. Six values is a short list to carry into an exam.
2A question says: “validate that a code is exactly 4 digits and starts with 7”. Write the pattern, then say what breaks if you leave out the anchors.
Show the solution
/^7[0-9]{3}$/
One 7, then three more digits — four in total. Writing {4} after the 7 would demand five.

Without the anchors, /7[0-9]{3}/ means “a 7 followed by three digits somewhere inside”, so xx7123yy passes.

The habit: without anchors a pattern searches; with anchors it measures.
3Sketch, in five lines, the shape every validation answer takes. No specific rule — only the skeleton.
Show the solution
const v = document.getElementById("box").value.trim();  // read
const msg = v === "" ? "Required"
       : !RULE.test(v) ? "Wrong format" : "";  // test
document.getElementById("err").innerHTML = msg;  // report
if (msg === "") { /* accept */ }  // decide
Read, test, report, decide. Seven of your twenty-two questions are this skeleton with a different RULE. Learn the skeleton and the rule is the only thing left to work out in the exam hall.
4Which of these can a regular expression not check, and what would you use instead? (a) an email shape  (b) two passwords matching  (c) at least 18 years old  (d) at least two boxes ticked
Show the solution
Only (a) is a pattern job.

(b) compares two values — p1 === p2.
(c) is arithmetic on dates — new Date() and a subtraction, with the month-and-day check.
(d) is counting elements — querySelectorAll then filter(b => b.checked).

The rule: a pattern only knows the characters in one box. Anything depending on a second value, a calculation, or the page itself needs ordinary code.
That is the unit. Eight syllabus phrases, twenty-two past questions, forty-five files that run. One module left, and it is the one where you find out what stuck.
Module 15 · Timed Self-Assessment and Answer Key · 22 min
CHUNK 1 OF 3 0:00 – 0:09

Ten minutes, eight questions, nobody watching

These eight mirror the real slot pattern — Q3, Q4, Q5, Q12(a), Q12(b) and Q16(b) are JavaScript in every paper. That is 18 of 60 marks, and you know where they are before you turn the page.
New folder 15-selftest inside FSWD-Unit2 · one file per question you answer in codeq1.html through q8.html · Ctrl+N then Ctrl+S, name it with .html · questions 2 and 3 are written answers — paper is fine
Close this page’s next chunk. Get paper, or a blank file. Ten minutes on a timer. The solutions are one press away and they will still be there afterwards — but the point is what you can do before you look.
Getting things wrong here is the entire point. A question you miss now is a mark you keep later. Nobody sees this, nothing is recorded, and there is no such thing as a bad score on a practice you do honestly.
YOUR SIX SLOTS · 18 OF 60 MARKS Q3 2 marks Q4 2 marks Q5 2 marks Q12(a) 4 marks Q12(b) 4 marks Q16(b) 4 marks the same six positions in all four papers — find them first, answer them first
Six slots, eighteen marks, entirely predictable

Start the timer

Question 1Q3 · Variables and data types2 marks
Declare a constant for a price of 60 and a variable for a quantity of 3. Increase the quantity by one and print the total using a template string. State why one is const and the other let.
Question 2Q4 · Predict the output2 marks
What does this print, and why?
function A(arg) {
  if (arg) console.log("true", arg === true);
  else    console.log("false", arg === false);
}
A("");
Question 3Q4 · Predict the output2 marks
What does this print?
console.log(count);
var count = 5;
console.log(typeof null, [] == false);
Question 4Q5 · Arrays2 marks
Given const n = [12, 3, 25, 8]; write one line each to get the values above 10, the total, and the list sorted smallest first. Say what n.sort() alone would give.
Question 5Q5 · Strings2 marks
From " Ms. Kavya Rao ", produce the salutation and the last name. Then say why name.toUpperCase(); on its own line changes nothing.
Question 6Q12(a) · Form validation4 marks
Write a complete page with one text box and a button that validates a pincode: exactly 6 digits, starting with 5. Show the error in red below the box and clear it when the value becomes valid. (A variant of the pincode question.)
Question 7Q12(b) · Events and functions4 marks
A page has two number boxes and a paragraph. Write a program that shows their sum in the paragraph as the user types in either box, with no button. Use an arrow function.
Question 8Q16(b) · DOM manipulation4 marks
What is the DOM? Then write a program that adds a new list item to a <ul> each time a button is pressed, numbered Item 1, Item 2 and so on, to a maximum of four, with an error message beyond that.
Ten minutes. Eight questions.
Then, and only then, the next chunk.
CHUNK 2 OF 3 0:09 – 0:16

Solutions — the two-mark questions

Compare against your own answer rather than reading these straight through. Where you differ, the interesting question is why — and the reason is usually one line back.
1Variables and data types
Solution · 2 marks
answers / q1.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>Total</title></head>
3<body>
4 <pre id="out"></pre>
5 <script>
6 const price = 60;
7 let qty = 3;
8
9 qty = qty + 1;
10
11 document.getElementById("out").innerHTML =
12 `${qty} at ${price} = ${qty * price}`;
13 </script>
14</body></html>
untitled×
127.0.0.1:5500/index.html
live
The mark is in the reason, not the code. price never changes, so const. qty is reassigned on line 9, so it must be let — assigning to a const throws TypeError: Assignment to constant variable. Say that sentence and the second mark is safe.
2Predict the output — A("")
Solution · 2 marks
false false
Step one — which branch? "" is one of the six falsy values, so the if fails and the else runs. The word printed is "false".

Step two — "" === false? A string against a boolean. Different types, so === says false without looking further.

The trap. The else ran because "" is falsy, which makes it feel like "" === false ought to be true. It is not. Being falsy is not the same as being false. Only false itself is === false — the other five falsy values are all something else.

Compare with the real PYQ in Module 13: A([]) gives true false because an empty array is truthy. Same function, opposite first word, and false both times for the second.
3Predict the output — hoisting and oddities
Solution · 2 marks
undefined
object true
Line 1 — undefined. var hoists the name but not the value, so count exists and holds undefined. With let this would throw instead.

typeof null is "object" — a bug from 1995 that can never be fixed because too much code depends on it.

[] == false is true — loose equality turns the array into "", then into 0, and false into 0. With === it would be false.
4Arrays
Solution · 2 marks
answers / q4.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>Arrays</title></head>
3<body>
4 <pre id="out"></pre>
5 <script>
6 const n = [12, 3, 25, 8];
7
8 const big = n.filter(v => v > 10);
9 const total = n.reduce((a, b) => a + b, 0);
10 const sorted = [...n].sort((a, b) => a - b);
11
12 document.getElementById("out").innerHTML =
13 `above 10: ${big}\ntotal: ${total}\nsorted: ${sorted}`;
14 </script>
15</body></html>
untitled×
127.0.0.1:5500/index.html
live
The second mark is the sort() answer. A bare n.sort() gives [12, 25, 3, 8] — it compares as text, so "12" comes before "3" the way a dictionary would order them. The comparator (a, b) => a - b is what makes it numeric.

[...n] copies first so the original is left alone.
5Strings
Solution · 2 marks
answers / q5.htmlruns
1<!DOCTYPE html>
2<html><head><meta charset="utf-8"><title>Name</title></head>
3<body>
4 <pre id="out"></pre>
5 <script>
6 const raw = " Ms. Kavya Rao ";
7 const s = raw.trim();
8
9 const parts = s.split(" ");
10 const salutation = parts[0];
11 const lastName = parts[parts.length - 1];
12
13 document.getElementById("out").innerHTML =
14 salutation + " / " + lastName;
15 </script>
16</body></html>
untitled×
127.0.0.1:5500/index.html
live
trim() first, or the leading spaces make split(" ") hand you an empty first piece.

The second part: name.toUpperCase(); on its own line changes nothing because strings cannot be edited in place. The method made a capitalised copy and handed it back, and nobody caught it, so it was thrown away. You need name = name.toUpperCase();.
Questions 2 and 3 are where the marks leak. Both are two-markers that take thirty seconds if you know the rule and cost you the whole question if you guess. Six falsy values, and var hoists as undefined — that is the entire syllabus for Q4.
CHUNK 3 OF 3 0:16 – 0:22

Solutions — the four-mark questions

6Form validation — pincode (a variant of the pincode question)
Solution · 4 marks
answers / q6.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Pincode</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 input { padding: 8px; width: 200px; }
9 button { padding: 8px 16px; background: skyblue; }
10 .error { color: red; font-size: 13px; min-height: 16px; }
11 </style>
12</head>
13<body>
14 <input id="pin" value="500031">
15 <p class="error" id="err"></p>
16 <button id="go">Check</button>
17 <p id="out"></p>
18
19 <script>
20 const PIN = /^5[0-9]{5}$/;
21
22 document.getElementById("go").onclick = () => {
23 const v = document.getElementById("pin").value.trim();
24 const err = document.getElementById("err");
25
26 const msg = v === "" ? "Pincode is required" :
27 !PIN.test(v) ? "6 digits, starting with 5" : "";
28
29 err.innerHTML = msg;
30 document.getElementById("out").innerHTML = msg === "" ? "Accepted" : "";
31 };
32 </script>
33</body></html>
untitled×
127.0.0.1:5500/index.html
live
try 400031, then 50003, then 500031
Count the characters. Six digits starting with 5 means 5 then five more — {5}, not {6}. Off-by-one in a quantifier is the most common mistake in this question.

The fourth mark is the clearing. Line 26 empties the error before showing the result. Leave it out and a corrected pincode still shows red.

.trim() and the empty check are each worth a mark on their own in most marking schemes.
7Events — a live sum
Solution · 4 marks
answers / q7.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Live sum</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 input { padding: 8px; width: 90px; margin-right: 6px; }
9 </style>
10</head>
11<body>
12 <input id="a" value="7">
13 <input id="b" value="5">
14 <p id="out"></p>
15
16 <script>
17 const add = () => {
18 const a = Number(document.getElementById("a").value);
19 const b = Number(document.getElementById("b").value);
20
21 document.getElementById("out").innerHTML =
22 (isNaN(a) || isNaN(b)) ? "Numbers only" : "Sum: " + (a + b);
23 };
24
25 document.getElementById("a").addEventListener("input", add);
26 document.getElementById("b").addEventListener("input", add);
27
28 add();
29 </script>
30</body></html>
untitled×
127.0.0.1:5500/index.html
live
type in either box — the sum updates immediately
input, not change. “As the user types” means every keystroke. change on a text box only fires when focus leaves it, so nothing would happen while typing — this is the mark the question is testing.

Number(...) on both. Without it you get "7" + "5" = "75", which is the classic wrong answer.

Line 26 calls add() once at the start so the paragraph is not blank before the first keystroke.
8DOM — add a list item, maximum four
Solution · 4 marks
answers / q8.htmlruns
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>Add items</title>
6 <style>
7 body { font-family: Arial; max-width: 400px; }
8 button { padding: 8px 16px; background: skyblue; }
9 .error { color: red; font-size: 13px; min-height: 16px; }
10 </style>
11</head>
12<body>
13 <button id="go">Add item</button>
14 <p class="error" id="err"></p>
15 <ul id="list"></ul>
16
17 <script>
18 const MAX = 4;
19 const list = document.getElementById("list");
20
21 document.getElementById("go").onclick = () => {
22 const items = list.querySelectorAll("li");
23
24 if (items.length >= MAX) {
25 document.getElementById("err").innerHTML =
26 "You cannot add more than " + MAX + " items";
27 return;
28 }
29
30 const li = document.createElement("li");
31 li.textContent = "Item " + (items.length + 1);
32 list.appendChild(li);
33 document.getElementById("err").innerHTML = "";
34 };
35 </script>
36</body></html>
untitled×
127.0.0.1:5500/index.html
live
press it five times — the fifth is refused
The definition first — that is one of the four marks. The DOM is the Document Object Model: the tree of objects the browser builds from the HTML file, which JavaScript can read and change. Changing the tree redraws the page; the file is never touched.

Three steps for the element: createElement, set it up, appendChild. Miss the third and nothing appears — and nothing complains.

Count from the page, not a variable. list.querySelectorAll("li").length stays right even if items are removed later. A separate counter drifts.
Q6 — the pattern is one mark of four. The other three are the reading, the reporting and the clearing. An answer that gets the regex perfect and forgets the rest scores one.
Q7 — two boxes, one handler, attached twice. Writing the logic once and adding it to both inputs is worth more than two near-identical handlers, and it is shorter.
Q7 — isNaN does not catch an empty box. Number("") is 0, not NaN, so an empty box counts as zero. Add a v === "" check if that should be refused.
Q8 — the numbering comes from the page. items.length + 1 reads the list as it stands, so it stays correct however the list was reached.
Q8 — the error clears on a successful add. Press four times, get refused on the fifth, then reload and add one: the message must not linger. Same fourth mark as Q6, in a different question.
In question 6
Worth
Most often missed
the pattern, with anchors
1 mark
{6} instead of {5} after the leading 5
reading with .trim() and an empty check
1 mark
trusting the box without trimming
showing the message in red, below the box
1 mark
using alert instead — the question said below the box
clearing it when the value becomes valid
1 mark
this one — most answers stop at showing the error
In the frame above
fix a bad pincode
the red text disappears and Accepted arrives

All twenty-two past questions, in one place

Every JavaScript question from the four papers you were given, with where it is worked. Press a badge to go there.
Paper · Q
The question
Worked in
15279 · Q3
Sort an array in descending order
15279 · Q4
Add a property city to an existing user object
15279 · Q12(a)
Read a text box, uppercase it, reject digits and @ # $
15279 · Q12(b)
map() against forEach(); filter objects by price, sort, display
15279 · Q16(b)
What is the DOM? A new text box per click, maximum five
15259 · Q3
Validate password and re-type password
15259 · Q4
Output of A([]) with ===
15259 · Q5
Arrow function to greet the user
15259 · Q12(a)
Validate 1602-YY-7YY-YYY@vce.ac.in, mail on link click
15259 · Q12(b)
Full name built on blur; alphabets only, not blank
15259 · Q16(b)
Calculator with a single text box, + and
15267 · Q3
Email: starts with a letter, 2–5 characters, then yahoo.com
15267 · Q4
Output of with(obj) { alert(y) }
15267 · Q5
Arrow function to sum the numbers in an array
15267 · Q12(a)
Validate date of birth (18+) and pincode (5 digits, starts 5)
15267 · Q12(b)
Student object with a grades array; average grade on a button click
15267 · Q16(b)
At least four of six course checkboxes
15252 · Q3
Name four data types in JavaScript
15252 · Q4
Create an array of different types of cars
15252 · Q12(a)
Use of let and const in ES6
15252 · Q12(b)
Full name from first and last; extract Dr./Mr./Ms.
15252 · Q16(b)
Username rules, and at least two of four checkboxes
Look down the middle column. Seven of the twenty-two are validation, four are the DOM, four are arrays. Three themes cover fifteen questions. If time is short before an exam, that is the order to revise in.

Your finished project

FSWD-Unit2 ├── 01-skeleton · 02-first-script · 03-variables · 04-functions · 05-objects ├── 06-arrays · 07-strings · 08-events · 09-validation · 10-registration ├── 11-dom · 12-window · 13-quirks · 14-bridge └── 15-selftest └── q1.html … q8.html your answers
Question 6 — the fourth mark is almost always the clearing. Most answers validate correctly and then forget to empty the error before showing success. Check yours.
Question 7 — if you used change rather than input, that is the whole question missed. Not a small slip: the phrase “as the user types” is the examiner pointing at input.
Question 8 — did you write the definition? One of the four marks is the sentence, not the program. Questions that begin “What is X? Then write…” always split their marks that way.
Across all three, did you count from the page or from a variable? querySelectorAll(...).length cannot drift. A counter you maintain yourself can.
If you scored under half, that is information, not a verdict. Look at which slots you lost — the badges in the table below take you straight to where each is worked slowly.
That is the unit, end to end. Sixteen modules, seventy-one chunks, forty-five files that run, and every past question worked. Whatever you scored on those eight, you can now read any JavaScript in your papers and know what it does. Go and build something.
Presenter> next< back full screen