What JavaScript Does
JavaScript transforms a static website (HTML + CSS) into a dynamic, interactive experience. Without JavaScript, a page is like a beautiful picture: it can look good but cannot respond to clicks, update content in real time, or fetch live data. JavaScript gives instructions to HTML elements — a script that tells each part what to do and when.
Real-world examples (all require JavaScript)
- Moneycontrol.com – interactive charts, live stock data, ads. Disabling JavaScript breaks chart rendering and removes ads.
- Timeanddate.com – a continuously ticking clock. Without JavaScript, the time freezes on page load.
- Flex (creative portfolio) – scroll-triggered animations, colour changes, horizontal scrolling, falling elements.
- Mission Mass – dynamic page transformations (scroll-driven direction changes).
These sites become unresponsive or broken when JavaScript is turned off.
A brief history
- 1995 – Netscape Navigator held >80% browser market share. Websites were static; every interaction required a server request.
- Netscape hired Brendan Eich, who created JavaScript in 10 days. Originally called LiveScript, renamed to JavaScript to capitalise on Java’s popularity (they are completely different languages).
- Standardised as ECMAScript (abbreviated ES). Modern versions: ES5, ES6 (and later).
- Today, sites like Twitter, YouTube, Netflix, and most of the web depend entirely on JavaScript.
How JavaScript works
Computers understand only binary (0s and 1s). JavaScript is a programming language that acts as a translator: we write human-readable instructions (e.g., alert("Hello")), and the browser’s JavaScript engine converts those instructions into machine code.
JavaScript code Browser engine Machine instructions
(human) → (interpreter) → (0s and 1s)
JavaScript is an interpreted language (runs line‑by‑line in the browser), unlike Java which is compiled.
Key takeaways
- JavaScript makes websites interactive (live updates, click responses, animations).
- It was created in 10 days at Netscape (1995) and standardised as ECMAScript.
- JavaScript is not related to Java; it runs in all major browsers.
- It translates our instructions into commands the browser can execute.
Where to write JavaScript
- Chrome DevTools Console – for quick one‑line tests.
- Open: Menu → More tools → Developer tools (or right‑click → Inspect → Console tab).
- Type
alert("Hello");and press Enter → a popup appears. - Use
Shift+Enterto write multiple lines before executing.
- Chrome DevTools Snippets – for longer code that can be saved and re‑run.
- Sources tab → Snippets (may need to click
>>to find it) → New snippet. - Write code, save, click Run (or
Ctrl/Cmd+Enter). - Output appears in a console at the bottom.
- Sources tab → Snippets (may need to click
- In HTML files (later modules) – JavaScript is added via
<script>tags in a.htmlfile, run with Live Server.
| Tool | Best for | Notes |
|---|---|---|
| Console | Quick tests, single expressions | Not saved; accidental Enter executes |
| Snippets | Multi‑line code, saved snippets | Saved in browser, easy to rerun |
HTML <script> | Full web pages | Used in later modules for DOM |
First command: alert()
alert("Hello");
alert("Hi");
alert("Hello boss");
alert– a built‑in keyword that calls a function (technicallywindow.alert()).- Parentheses
()– hold the argument (the message). - Quotation marks
" "or' '– enclose a string (text). - Semicolon
;– marks the end of an instruction (like a full stop). Always include it.
If you type an invalid command, e.g., sayHi, the browser returns:
Uncaught ReferenceError: sayHi is not defined
Using MDN documentation
To verify valid JavaScript commands and learn details, search MDN JavaScript (Mozilla Developer Network).
Example: search “MDN alert” to see the full specification, variants like open(), focus(), prompt(), etc.
Exam tip:
alert()is a method of thewindowobject, but you can write justalert(). Semicolons are optional in many cases, but using them consistently prevents errors.
Key takeaways
- Use Chrome DevTools Console for one‑liners, Snippets for longer code.
alert()syntax: keywordalert, parentheses, quoted message, semicolon.- Semicolon ends a statement.
- Use MDN as the authoritative reference for JavaScript methods and syntax.
Data Types in JavaScript
Data types define the kind of value a variable can hold — like a water bottle holds water, a box holds toys. In JavaScript, every value has a type, and knowing the type tells you what operations you can perform.
String
A string is a sequence of characters used to represent text. Strings are enclosed in single quotes ('), double quotes ("), or backticks (`).
"Govind" // double quotes
'IIM Bangalore' // single quotes
`IIMB space` // backticks
'' // empty string - still a string
"1234" // digits in quotes - still a string
- Strings can contain letters, numbers, symbols, and special characters (e.g.,
\nfor newline). - Useful for messages, user input, and joining text (concatenation).
Number
A number represents numeric values — integers and decimals alike. JavaScript treats all numbers as the same type (no separate integer/floating distinction).
25
4.5
- Arithmetic operations (
+,-,*,/) work on numbers. - If you wrap digits in quotes (e.g.,
"25"), they become a string, not a number.
Boolean
A boolean has only two possible values: true or false. It is used for decisions and conditional logic.
true
false
- Often results from comparisons (e.g.,
5 > 3→true).
The typeof Operator
Use the typeof operator to check the data type of a value. It is an operator, not a function — no parentheses needed.
typeof "hello" // "string"
typeof 42 // "number"
typeof true // "boolean"
typeof "" // "string"
typeof "1234" // "string" (because quoted)
Exam tip:
typeofis an operator, not a function. Common mistake: writingtypeof(x)— while it works, the correct form istypeof x. Prefer the operator form.
Why Data Types Matter
- Operations behave differently per type: adding numbers sums them; adding strings joins them.
- Knowing the type helps avoid bugs, especially when data comes from user input or external APIs.
typeofis your first debugging tool to confirm what you're working with.
Key takeaways
- String – text in quotes (
"",'', backticks). - Number – any numeric value (no separate integer/decimal).
- Boolean –
trueorfalse. typeof– operator to return the type as a string.- Same literal (e.g.,
25vs"25") can be number or string depending on quotes.
Variables in JavaScript
A variable is a labelled container that stores a value so you can reuse or change it later. Think of it as a box with a label, or a tentacle that grabs a value and can later grab a different one.
Declaring Variables
Three keywords create variables:
| Keyword | Use case | Can reassign? |
|---|---|---|
let | Modern, value may change | Yes |
var | Older style, similar to let but different scope | Yes |
const | Value must stay constant | No (error on reassignment) |
Syntax: keyword variableName = value;
let name = "Govind"; // declare + assign
let month = "January";
const birthYear = 1990; // cannot change later
var price = 200; // older way
- Variable names should be meaningful (
citynotx). - Use
letby default in modern code; useconstwhen the value is fixed.
Assignment and Reassignment
- Declaration creates the variable (using
let,var, orconst). - Assignment gives it a value with
=. - Reassignment changes the value without repeating the keyword.
let city = "Mumbai";
city = "Bangalore"; // reassign – no let/var/const
With const, reassignment throws an error:
const name2 = "Govind";
name2 = "Raj"; // ❌ TypeError: Assignment to constant variable
Reading Variable Values
Use the variable name anywhere you need its value:
let age = 99;
age; // → 99
console.log() – Viewing Values
The console.log() function prints values to the console. It accepts literals (in quotes) or variable names (without quotes).
let greeting = "Hello, welcome!";
console.log(greeting); // prints the variable's value
console.log("Hello"); // prints a string literal
console.log(10); // prints a number
- Essential for debugging and understanding what your code is doing.
Undefined Variables
Referencing a variable that was never declared causes a ReferenceError:
console.log(country); // ❌ country is not defined
Declare it first:
let country = "India";
console.log(country); // → India
Key takeaways
- Variables are containers; declare with
let,var, orconst. letandvarallow reassignment;constdoes not.- Syntax:
let name = value;– keyword, name,=, value, semicolon. - Reassign without repeating the keyword:
name = newValue; console.log()prints values — use it for debugging.- Accessing an undeclared variable throws an error.
Variables with Alert and Prompt
Alert and prompt are built‑in browser functions that let a JavaScript program communicate with the user. Alert displays a message (popup with an OK button). Prompt asks for input and returns whatever the user types.
Intuition: you want a tiny conversation — ask the user something, store their answer, then respond using that answer.
Syntax
alert("Your message here");
let variableName = prompt("Question for the user");
- alert – takes one string argument; shows the string in a pop‑up.
- prompt – takes one string argument (the question); returns the string the user typed (or
nullif cancelled).
Worked Example – Greet the User
let username = prompt("What is your name?");
alert("Hi " + username + ", welcome to this course.");
Flow:
If the user enters “Shahrukh”, the alert shows: Hi Shahrukh, welcome to this course.
String Concatenation
The + operator joins (concatenates) strings together.
"Hi " + username + ", welcome" becomes one continuous string.
Exam tip: When a variable holds a number (e.g. from
prompt), it is actually a string by default. Concatenation still works, but be aware that"5" + 3="53"(string), not8.
Second Example – Age
let age = prompt("What is your age?");
alert("Wow, you are " + age + " years old.");
You can reuse the same variable in multiple places:
alert("Wow " + username + ", you are " + age + " years old.");
Key Takeaways
- alert displays a message; prompt gets user input.
- prompt returns a string; store it in a variable for later use.
- Use
+to concatenate strings and variables. - Combining prompt and alert creates simple interactive programs.
- Variables become dynamically assigned – their value comes from user input at runtime.
Variable Naming Rules and Camel Case
Good variable names make code readable and maintainable. JavaScript has strict rules and community conventions.
Allowed Characters
- Letters (a–z, A–Z)
- Digits (0–9) – but cannot start with a digit
- Underscore (
_) and dollar sign ($) – avoid both at the start (underscore has special meaning in many contexts)
let name = "Govind"; // valid
let NAME = "Raj"; // different variable (case‑sensitive)
let name123 = "Lakshmi"; // valid
let 1name = "error"; // ❌ SyntaxError
What to Avoid
| Rule | Why |
|---|---|
No special characters (@,#,%) | Cause syntax errors |
| No spaces | let user age → unexpected number |
| No JavaScript reserved words | let, const, function, if, etc. |
No starting with _ (convention) | Reserved for internal/protected properties |
| No starting with a digit | Illegal token |
Exam tip: Reserved words include
break,case,catch,class,const,continue,debugger,default,delete,do,else,export,extends,finally,for,function,if,import,in,instanceof,let,new,return,super,switch,this,throw,try,typeof,var,void,while,with,yield. Never use them as variable names.
Case Sensitivity
name and NAME are two different variables. JavaScript is case‑sensitive.
Lower Camel Case (Recommended Convention)
Start with a lowercase letter; capitalise the first letter of each subsequent word.
let userName = "Govind"; // camelCase
let userAge = 21;
let cityOfResidence = "Mumbai";
let workOfArt = "picasso";
Without camelCase: workofart could be misread as work of art or workof art.
With camelCase: workOfArt is instantly clear.
Best Practices
- Descriptive –
let totalItemsinstead oflet x. - Concise – avoid overly long names like
totalNumberOfElementsInCart; usetotalItems. - Consistent – stick to camelCase throughout your project.
- Meaningful – the name should indicate what data the variable holds.
Dynamic Typing
JavaScript does not require you to declare a data type. The type is determined by the assigned value – and can change later.
let age = 25; // number
age = "twenty five"; // now string – no error
This flexibility is powerful but can cause bugs. Clear naming helps you (and others) keep track of what type is expected.
Key Takeaways
- Variable names: letters, digits (not first),
_,$. No spaces, no reserved words. - Case‑sensitive –
myVar≠myvar. - Use lower camelCase –
userName,totalPrice. - Be descriptive yet concise.
- JavaScript is dynamically typed – same variable can hold different types.
Variable Reassignment
Variable reassignment means giving a new value to a variable that already exists. A variable’s value can be changed at any time, and assigning one variable to another copies the current value (for primitive types like strings and numbers). This is a foundational concept for understanding how JavaScript stores and manages data in memory.
Swapping values
A classic task is swapping the values of two variables (e.g., cup1 = "coffee", cup2 = "tea" → swap so cup1 holds "tea" and cup2 holds "coffee").
Method 1: using a temporary (third) variable
- Store the value of
cup1into a third variablecup3. - Assign
cup1the value ofcup2. - Assign
cup2the value ofcup3.
let cup1 = "coffee";
let cup2 = "tea";
let cup3; // empty cup
cup3 = cup1; // cup3 = "coffee"
cup1 = cup2; // cup1 = "tea"
cup2 = cup3; // cup2 = "coffee"
After the swap: cup1 → "tea", cup2 → "coffee", cup3 still holds "coffee".
How copying works: When we wrote
cup3 = cup1, the value"coffee"was copied intocup3. Changingcup1later (e.g.,cup1 = "juice") does not affectcup3– each variable has its own independent memory slot.
Method 2: arithmetic swap (numbers only)
For numeric variables, values can be swapped without an extra variable using addition and subtraction.
let x = 5, y = 10;
y = x + y; // y = 5 + 10 = 15
x = y - x; // x = 15 - 5 = 10
y = y - x; // y = 15 - 10 = 5
console.log(x, y); // 10, 5
Why it works: The trick uses the sum as a temporary storage. After the first step, y holds the sum (x + y); then x becomes the original y (sum – original x), and finally y becomes the original x (sum – new x).
Exam tip: The arithmetic swap is a clever trick but only works for numbers (and can fail with very large values causing overflow, or with floats). In real code, use a temporary variable – it’s clearer and works for any type.
Key insight: primitive values are copied, not referenced
When you assign let a = b for primitive values (strings, numbers, booleans, null, undefined, Symbol, BigInt), JavaScript copies the value. The two variables become completely independent:
let x = 2;
let y = x; // y = 2 (a copy)
x = 10; // x changes, but y remains 2
console.log(y); // 2
This applies to the cup example: after the swap, cup3 still holds "coffee". If you later write cup3 = "juice", cup2 does not change.
Contrast with objects: Objects and arrays are stored by reference, not copied.
Key takeaways
- Assigning a primitive variable to another copies the value – each variable has its own memory slot.
- Swapping values can be done with a temporary variable (any type) or with arithmetic (numbers only).
- After a copy, modifying one variable does not affect the other.
- The arithmetic swap trick is efficient but limited – know it as an exercise, but prefer the temp-variable method in practice.
Strings: Indexing, Properties, Concatenation
A string is an ordered sequence of characters used to represent text. In JavaScript, strings can be written with double quotes (" "), single quotes (' '), or backticks (` `). All are equivalent – the choice is stylistic.
Indexing and Bracket Notation
Computers count positions starting at zero – this is zero-based indexing.
Take let greeting = "Hello".
The character–index mapping:
| Character | Index |
|---|---|
| H | 0 |
| e | 1 |
| l | 2 |
| l | 3 |
| o | 4 |
To retrieve a character, use bracket notation: string[index].
greeting[0]→"H"greeting[1]→"e"greeting[4]→"o"
If the index exceeds the last valid position, JavaScript returns undefined – no error is thrown, the program continues.
greeting[99]→undefined
Exam tip: Accessing out-of-bounds always gives
undefined, not an error. This is a frequent interview and exam question.
The .length Property
The length property returns the total number of characters in the string. It is a property, not a method – no parentheses.
"Hello".length→5- The highest valid index is always
length - 1(here,4).
Because indexing starts at zero, length is one greater than the last index. For "Simran" (6 characters), Simran.length = 6 and Simran[5] = "n".
Concatenation and Type Coercion
Strings can be joined with the + operator – this is concatenation.
"Raj" + " Simran" → "Raj Simran"
When a string and a number are added, JavaScript performs type coercion: it converts the number to a string before concatenating.
"1" + 1→"11"(string)"Hello" + 42→"Hello42"
This can lead to unexpected results:
| Expression | Result | Explanation |
|---|---|---|
"1" + 1 | "11" | Number 1 coerced to string |
1 + "1" | "11" | Same coercion |
1 + 1 + "2" | "22" | Left-to-right: 1+1=2, then 2 + "2" = "22" |
"2" + 1 + 1 | "211" | Left-to-right: "2" + 1 = "21", then "21" + 1 = "211" |
Exam tip: Avoid mixing strings and numbers in the same expression. If concatenation is intended, convert numbers manually with
String(n)or.toString()to make intent clear.
Immutability
Strings are immutable – once created, their individual characters cannot be changed by assigning to an index.
let animal = "cat";
animal[0] = "b"; // no error, but does nothing
console.log(animal); // still "cat"
To modify a string, you must reassign the entire variable:
animal = "bat"; // works
This applies to all string manipulations – any operation that appears to change a string actually returns a new string.
Key takeaways
- Strings are zero-indexed; use
str[i]to access characters. - Out-of-bounds indexing yields
undefined, not an error. .lengthgives the character count (not the highest index).+joins strings; mixing numbers and strings causes type coercion — be explicit.- Strings are immutable – direct character assignment fails; reassign the whole string.
String Methods
String methods are functions attached to string objects that perform actions on text — converting case, trimming whitespace, searching, extracting, replacing, and more. Unlike string properties (e.g., .length), methods do work and always end with parentheses (). Most string methods do not modify the original string; they return a new string instead.
Syntax
string.method(arg1, arg2, ...)
stringcan be a variable or a string literal.- The parentheses may contain optional arguments — values that control the method's behaviour.
Common string methods at a glance
| Method | What it does | Returns |
|---|---|---|
.toUpperCase() | Converts all characters to uppercase. | New string |
.toLowerCase() | Converts all characters to lowercase. | New string |
.trim() | Removes whitespace from both ends. | New string |
.indexOf() | Finds the first index of a substring (search from start). | Number or -1 |
.slice() | Extracts a part of the string (by index). | New string |
.replace() | Replaces the first occurrence of a substring with another. | New string |
.repeat() | Repeats the string a specified number of times. | New string |
Exam tip:
.indexOfreturns-1when the substring is not found — a common bug if you forget to check for that.
1. Changing Case: .toUpperCase() and .toLowerCase()
Intuition: Convert text to all caps or all lowercase, e.g., for normalising user input.
Examples :
let name = "govind";
console.log(name.toUpperCase()); // "GOVIND"
console.log(name); // "govind" (original unchanged)
let shout = "Hello!";
console.log(shout.toLowerCase()); // "hello!"
2. Cleaning Whitespace: .trim()
Intuition: Remove accidental spaces before/after user input — common in form data.
Behaviour: Removes spaces, tabs, newlines from both ends. Returns a new string.
let badInput = " hello world ";
let clean = badInput.trim();
console.log(clean); // "hello world"
console.log(badInput); // " hello world " (unchanged)
3. Searching: .indexOf(substring, start?)
Intuition: Find where a piece of text first appears inside a string. Useful for checking existence or extracting from a known point.
- Returns the index (0-based) of the first occurrence of
substring. - The optional second argument –
start– tells the method to begin searching from that index. - Returns
-1ifsubstringis not found.
Examples:
let paragraph = `I think Ruth's dog is cuter than your dog.`;
console.log(paragraph.indexOf("T")); // 2
console.log(paragraph.indexOf("TH")); // 2
console.log(paragraph.indexOf("dog")); // 13
console.log(paragraph.indexOf("dog", 14)); // 37 (starts searching from index 14)
console.log(paragraph.indexOf("cat")); // -1 (not found)
4. Extracting a Substring: .slice(start, end?)
Intuition: Cut out a portion of a string by index — like a pair of scissors for text.
- If only
startgiven: returns from that index to the end. - If
startandendgiven: returns fromstartup to but not includingend. - Negative indices count from the end of the string (
-1= last character).
Examples:
let paragraph = "I think Ruth's dog is cuter than your dog.";
console.log(paragraph.slice()); // whole string
console.log(paragraph.slice(5)); // "nk Ruth's dog is cuter than your dog."
console.log(paragraph.slice(5, 10)); // "nk Ru"
console.log(paragraph.slice(-2)); // "g."
console.log(paragraph.slice(-10)); // " your dog."
Exam tip:
.slice()does not modify the original string — always store the result in a new variable.
5. Replacing Text: .replace(search, replacement)
Intuition: Find a specific substring and swap it with something else. Only the first match is replaced.
search: the substring (or regex) to look for.replacement: the new string to put in its place.
Examples:
let paragraph = "I think Ruth's dog is cuter than your dog.";
let newPar = paragraph.replace("dog", "cat");
console.log(newPar); // "I think Ruth's cat is cuter than your dog."
// Only the first "dog" changed.
// Replace only part of a word
let partial = paragraph.replace("do", "DE");
// "I think Ruth's DEg is cuter than your dog."
For advanced replacements (all occurrences, case-insensitive), use regular expressions.
6. Repeating Text: .repeat(count)
Intuition: Generate a string repeated
counttimes – useful for padding, ASCII art, or test data.
console.log("ha".repeat(3)); // "hahaha"
Chaining Methods
Because each method returns a new string, you can call another method on the result — forming a method chain. This makes code concise.
Without chaining:
let corrected = badInput.trim();
let upper = corrected.toUpperCase();
With chaining:
let best = badInput.trim().toUpperCase();
console.log(best); // cleaned and uppercased, all in one line
The order matters: first trim, then uppercase (or vice versa – both work here).
Key Takeaways
- String methods are called with parentheses; properties (like
.length) are not. - Most methods return a new string and leave the original untouched – always capture the result in a variable.
.indexOfreturns-1when not found..slice(start, end)does not include the character atend..replaceonly replaces the first match (use regex for global).- Method chaining lets you combine multiple operations in one expression.
- MDN Web Docs is the authoritative reference for all string methods – bookmark it.
String Template Literals
Template literals are a cleaner, more readable way to create strings in JavaScript when you need to embed variables or expressions. Instead of glueing pieces together with +, you use backticks (`) and placeholders written as ${ ... }.
The problem: concatenation
let name = "Govind";
let age = 99;
let city = "Bangalore";
let country = "India";
alert("Hi " + name + " from " + city + ", " + country + "! Welcome here to our tutorial.");
This works, but:
- Hard to read and write – many
+signs and manual spacing. - Adding apostrophes or special characters forces quote changes.
- Long strings become error‑prone.
Template literal syntax
Use backticks instead of single or double quotes. Inside, any ${ expression } is evaluated and converted to a string automatically.
alert(`Hi ${name} from ${city}, ${country}! Welcome here to our tutorial.`);
| Feature | Old concatenation | Template literal |
|---|---|---|
| Quote style | ' or " | ` (backtick) |
| Variable insertion | "..." + var + "..." | `${var}` |
| Expression insertion | Must pre‑compute | `${2 + 4}` → "6" |
| Multi‑line strings | Need \n | Just press Enter inside backticks |
Exam tip: Template literals only work with backticks. Using single or double quotes will treat
${...}as literal text, not an expression.
Embedding any expression
Anything inside ${ } is a valid JavaScript expression – variables, arithmetic, function calls, even conditional logic. The result is coerced to a string.
let price = 25;
alert(`The price for ${ask} is $${price}.`); // → The price for eggs is $25.
To include a literal dollar sign, write $ before the placeholder – only ${ triggers evaluation.
Multi‑line strings
Template literals preserve line breaks. No \n needed.
alert(`Hi
Yes`);
// Output:
// Hi
// Yes
Key takeaways
- Template literals use backticks (
`) and${...}placeholders. - They replace cumbersome
+concatenation. - Any expression inside
${}is evaluated and string‑coerced. - Multi‑line content is natural – just hit Enter.
- Always use backticks; single/double quotes do not support template syntax.
Null and Undefined
Both represent “nothing” but are used in different scenarios.
| Concept | Who sets it? | Meaning | typeof |
|---|---|---|---|
undefined | Automatically by JavaScript | A variable has been declared but not assigned; a missing property. | "undefined" |
null | Explicitly by the programmer | “I intend to leave this empty.” | "object" (historical quirk) |
Undefined
JavaScript assigns undefined when something hasn’t been defined yet.
let x;
console.log(x); // undefined
Also appears when:
- Accessing a non‑existent array index:
"abc"[10]→undefined - A function returns nothing:
function f() {}→undefined
Null
You assign null to indicate a variable is intentionally empty.
let y = null;
console.log(y); // null
typeof y; // "object" (this is a long‑standing JS bug, but testable)
Exam tip:
nullis an object type in JavaScript – a historical mistake.undefinedis its own type. They are loosely equal (null == undefined→true) but strictly not equal (null === undefined→false).
When to use each
- Use
nullwhen you want to explicitly say “no value here” (e.g., future assignment, cleared data). - Let JavaScript give you
undefinedwhen something is missing – you do not usually assignundefinedyourself.
Key takeaways
nullis programmer‑set;undefinedis JS‑set.typeof null→"object";typeof undefined→"undefined".- Both mean “nothing”, but context matters.
- Loosely equal (
==), but strict equality (===) isfalse.
Numerical Operators
JavaScript provides arithmetic operators to perform basic math on numbers. Intuition: these work like a calculator but live inside code, operating on variables or literal values.
Arithmetic Operators
| Operator | Name | Example (x=10, y=20) | Result |
|---|---|---|---|
+ | Addition | x + y | 30 |
- | Subtraction | x - y | -10 |
* | Multiplication | x * 5 | 50 |
/ | Division | y / 5 | 4 |
** | Exponentiation (power) | x ** 2 | 100 |
% | Modulus (remainder) | 10 % 3 | 1 |
Modulus is especially useful for checking divisibility — e.g., a number is even if
number % 2 === 0.
Order of Operations (Operator Precedence)
JavaScript follows the same precedence as standard math: Parentheses → Exponents → Multiplication/Division → Addition/Subtraction (PEMDAS / BODMAS). Evaluation is left-to-right for operators of equal precedence.
Best practice: Use parentheses () to make intent explicit, even when precedence is clear.
(5 + 2) * 3→ clearly first add, then multiply.5 + 2 * 3→11(multiply first:2*3=6, then5+6=11).
Special Operators
Increment (++) and Decrement (--)
- Increase or decrease a variable by exactly 1.
- Only work on variables (not on literals like
5++). - Modify the variable in place.
let x = 10;
x++; // x becomes 11
x--; // x becomes 10 again
Compound Assignment Operators
Used to modify a variable by a larger amount concisely.
| Operator | Equivalent to | Example (starting x=10) |
|---|---|---|
x += 4 | x = x + 4 | x → 14 |
x -= 5 | x = x - 5 | x → 5 |
x *= 2 | x = x * 2 | x → 20 |
x /= 2 | x = x / 2 | x → 5 |
Exam tip:
++and--change the variable itself. They can be used in expressions; prefix versus postfix matters.
Worked Example: Check if a number is even
let num = 21;
if (num % 2 === 0) {
console.log("even");
} else {
console.log("odd");
}
// Output: odd
Key takeaways
- Six core arithmetic operators:
+, -, *, /, **, %. - Use
%to get remainder;num % 2 === 0tests evenness. - Order: Parentheses → Exponents → MD → AS. Use parentheses for clarity.
++and--increment/decrement by 1 on variables.- Compound assignment (
+=,-=,*=,/=) shortensx = x op value.
Math Object
The Math object is a built-in JavaScript collection of properties (constants) and methods (functions) for common mathematical operations. Intuition: you don't have to write your own square root or PI — the browser gives them to you.
Access via Math (capital M) followed by a dot and the property/method name.
Properties (constants)
| Property | Value |
|---|---|
Math.PI | 3.141592653589793 |
Methods
Rounding
| Method | Behaviour | Example | Result |
|---|---|---|---|
Math.round(x) | Rounds to nearest integer | Math.round(3.43) → 3; Math.round(5.55) → 6 | |
Math.floor(x) | Rounds down to lower integer | Math.floor(5.9999) → 5 | |
Math.ceil(x) | Rounds up to higher integer | Math.ceil(3.43) → 4 |
Other Common Methods
| Method | Purpose | Example | Result |
|---|---|---|---|
Math.abs(x) | Absolute value (removes sign) | Math.abs(-1) | 1 |
Math.sqrt(x) | Square root | Math.sqrt(4) | 2 |
Math.pow(base, exp) | Exponentiation (base**exp) | Math.pow(2,3) | 8 |
Math.random() | Random decimal between 0 (inclusive) and 1 (exclusive) | Math.random() | e.g. 0.732 |
Generating Random Integers (Worked Example)
Goal: a random integer between 1 and 10 (inclusive).
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Simplified for 1–10:
let rand = Math.floor(Math.random() * 10) + 1;
Why it works:
Math.random()→0.0to0.999...- Multiply by 10 →
0.0to9.999... Math.floor()→ integer0to9- Add
1→ integer1to10
Exam tip: to get a random integer in
[min, max], the general formula isMath.floor(Math.random() * (max - min + 1)) + min.
Practical Example: Circumference of a Circle
let radius = 25;
let circumference = 2 * Math.PI * radius;
console.log(circumference); // 157.07963267948966
Chaining Methods
Methods can be nested, executed inside-out:
let result = Math.floor(Math.sqrt(Math.abs(-999)));
// 1. Math.abs(-999) → 999
// 2. Math.sqrt(999) → 31.606...
// 3. Math.floor(31.606) → 31
console.log(result); // 31
Key takeaways
Math.PIgives π.- Three rounding methods:
round(nearest),floor(down),ceil(up). abs,sqrt,poware standard math helpers.Math.random()returns[0,1); useMath.floor(Math.random() * N) + 1for integers 1..N.- Chaining methods works inside-out; keep code readable with parentheses.
Logical Operators
Logical operators let you combine multiple conditions into a single expression that evaluates to true or false. They are the building blocks of decision‑making in JavaScript — everything from showing a cart count (“1 item” vs. “0 items”) to checking whether a user meets all requirements for a license.
Before understanding logical operators, you must master comparison operators, which compare two values and return a boolean.
Comparison operators
| Operator | Meaning | Example | Result |
|---|---|---|---|
< | Less than | 3 < 4 | true |
> | Greater than | 3 > 4 | false |
<= | Less than or equal to | 10 <= 10 | true |
>= | Greater than or equal to | 9 >= 10 | false |
== | Loose equality (type coercion allowed) | 10 == '10' | true |
=== | Strict equality (type must also match) | 10 === '10' | false |
!= | Loose inequality | 10 != '10' | false |
!== | Strict inequality | 10 !== '10' | true |
Loose equality (==) coerces one value to match the other’s type (e.g., string '10' becomes number 10). This can lead to surprising results:
'' == 0 // true (empty string is coerced to 0)
false == 0 // true
Exam tip: Always prefer strict equality (
===) and strict inequality (!==) in your code. They behave predictably because they do not perform type coercion. Loose equality is rarely needed and often a source of bugs.
Logical operators — truth tables
JavaScript provides three logical operators: AND (&&), OR (||), NOT (!).
| A | B | A && B | A || B | !A |
|---|---|---|---|---|
true | true | true | true | false |
true | false | false | true | false |
false | true | false | true | true |
false | false | false | false | true |
&&(AND) →trueonly when both sides aretrue.||(OR) →truewhen at least one side istrue.!(NOT) → inverts the boolean value.
Short‑circuit evaluation
&& stops evaluating as soon as it finds a falsy operand. || stops as soon as it finds a truthy operand. This is important for performance and for avoiding side effects, but for now focus on the boolean result.
Worked examples
1. Driving license eligibility (AND)
let age = 25;
let hasLL = true; // has learner's license
let eligible = (age >= 18) && (hasLL === true);
console.log(eligible); // true
If either condition fails (e.g., age = 17 or hasLL = false), the result is false.
2. Club entry (OR)
let age = 9;
let hasSpecialPermit = true;
let allowed = (age > 10) || (hasSpecialPermit === true);
console.log(allowed); // true (permit overrides age)
Only when both are false (age <= 10 and no permit) the result is false.
Comparing strings with logical operators
Strings can be compared with <, >, <=, >=. JavaScript compares them character by character based on their Unicode code points.
'B' > 'A' // true (Unicode 66 > 65)
'a' > 'A' // true (97 > 65)
Capital letters have lower Unicode values than lowercase letters, so 'A' < 'a' is true. This can be unintuitive — always test string comparisons in your specific context.
Key takeaways
- Logical operators (
&&,||,!) combine or invert booleans; understand their truth tables. - Comparison operators (
<,>,<=,>=,===,!==) return booleans; always prefer strict equality (===/!==) over loose equality. - Loose equality (
==) coerces types — can produce unexpected results like'' == 0. - Strings are compared by Unicode values:
'A' < 'a','B' > 'A'. - Practise combining conditions with
&&and||to solve real‑world eligibility checks (age + license, special permit, etc.).
Conditional Statements
Conditional statements allow code to execute only when a condition evaluates to true. They control the flow of execution based on variable states or logical checks — the program decides what to run, when.
The if Statement
Syntax:
if (condition) {
// code runs if condition is true
}
ifis a keyword;conditionmust be a boolean (true/false).- Curly braces
{}form a block; no semicolon after the closing brace. - Statements before and after the
ifblock always execute in normal top‑to‑bottom order.
Example – hot day check:
let temperature = 31;
if (temperature > 30) {
console.log("This is a hot day");
}
Output: "This is a hot day" only when temperature > 30.
if…else if…else Chain
For multiple conditions, use else if and optionally a final else as a default.
Syntax:
if (condition1) {
// block A
} else if (condition2) {
// block B
} else if (condition3) {
// block C
} else {
// default – runs if no condition above is true
}
Execution rule: Only the first block whose condition is true executes; all subsequent conditions are skipped. else runs only if no preceding condition is true.
Example – temperature classifier:
let temperature = 21;
if (temperature < 20) {
console.log("Normal day");
} else if (temperature < 25) {
console.log("Kind of hot day");
} else if (temperature < 30) {
console.log("Hot day");
} else {
console.log("Crazy hot day");
}
21→ first conditionfalse, secondtrue→"Kind of hot day".100→ all threeelse ifconditionsfalse→"Crazy hot day".
Example – marks grading:
let marks = 95;
if (marks > 95) {
alert("Excellent marks");
} else if (marks > 80) {
alert("Great marks");
} else {
alert("You can do better");
}
With 95: first condition false, second true → "Great marks". Even if later conditions are also true, only the first matching block executes.
Chain vs. Multiple Separate if Statements
| Structure | Behavior |
|---|---|
if…else if…else | Only one block runs (first true condition). |
Multiple standalone if | Each if is independent; all true conditions execute. |
Example – separate ifs:
if (temperature < 20) console.log("Normal"); // runs if true
if (temperature < 25) console.log("Kind of hot"); // also runs if true
For temperature = 10, both print. With a chain, only the first would print.
Nesting if Statements
An if block can contain another if…else structure for hierarchical decisions.
Example – driving license eligibility:
let age = 25;
let hasLL = "Y";
if (age >= 18) {
if (hasLL === "Y") {
alert("You can take DL");
} else {
alert("First get a LL");
}
} else {
alert("Grow older");
}
- Outer
ifchecks age eligibility first. - Only if
age >= 18does the innerifcheck for a learner’s license.
Alternative using else if (without nesting):
if (age >= 18 && hasLL === "Y") {
alert("You can take DL");
} else if (age >= 18 && hasLL !== "Y") {
alert("First get a LL");
} else {
alert("Grow older");
}
Both achieve the same logic; choose nesting when conditions are naturally grouped.
Logical Operators in Conditions
Combine multiple sub‑conditions with && (AND), || (OR), ! (NOT). They can be written directly in the condition or pre‑stored in a variable.
if (age >= 18 && hasLL === "Y") { ... }
Exam tip: In an
if…else ifchain, order matters. When overlapping ranges exist (e.g.,marks > 95andmarks > 80), the first true condition executes and the rest are ignored. Always test edge cases likemarks = 96where both could be true.
Key Takeaways
ifruns code only when its condition istrue.else ifadds additional conditions;elseis the default catch‑all.- In a chain, only one block executes — the first true one.
- Separate
ifstatements are independent and may both run. - Nesting places an
ifinside anotherifto handle hierarchical decisions. - Use logical operators (
&&,||,!) to combine conditions.
Nested Conditionals
Nested conditionals are if statements placed inside another if (or else/else if) block. They allow decisions that depend on multiple layers of conditions — the inner check only matters if the outer condition is true.
Structure
if (outerCondition) {
if (innerCondition) {
// runs when both true
} else {
// outer true, inner false
}
} else {
// outer false
}
Worked example: Movie ticket pricing
A cinema charges different prices based on two factors: age (≥18 or <18) and membership (Y/N). Without nesting, four separate conditions would be needed. Nesting makes the dependency explicit.
let age = parseInt(prompt("What is your age?"));
let member = prompt("Are you a member? (Y/N)");
if (age > 18) {
if (member === "Y") {
alert("Your ticket price is 200");
} else {
alert("Your ticket price is 300");
}
} else {
// age <= 18
if (member === "Y") {
alert("Your ticket price is 50");
} else {
alert("Your ticket price is 100");
}
}
The logic flows as:
Input validation with isNaN()
User input from prompt() is always a string. Use parseInt() to convert to a number, then check with isNaN() to ensure a valid numeric entry. Wrap the entire nesting inside an if (!isNaN(age)) block.
if (!isNaN(age)) {
// nested conditionals here
} else {
alert("Please enter a valid age");
}
Benefits & drawbacks
| Benefit | Drawback |
|---|---|
| Handles dependent conditions cleanly | Readability suffers as nesting depth increases |
| Avoids repeating outer checks | Debugging becomes harder |
| Matches natural decision hierarchies | Overuse leads to "spaghetti logic" |
Exam tip: When asked to simplify nested code, consider using logical operators (
&&,||) to flatten conditions. For the ticket example, the price could be computed with a single expression:if (age > 18) ? (member === "Y" ? 200 : 300) : (member === "Y" ? 50 : 100)— but nesting is clearer for beginners.
Key takeaways
- Nested
ifs let you test conditions that depend on earlier results. - Always validate numeric input with
parseInt()+isNaN(). - Keep nesting shallow (≤3 levels) to maintain readability.
- Example: ticket price depends on age first, then membership.
Truthiness
Truthiness refers to how JavaScript treats a non‑boolean value as true or false when used in a boolean context (e.g., inside an if condition). Not every value is a literal true or false, but every value behaves as one of them.
Falsy values (the complete list)
Only these six (plus 0n for BigInt) evaluate to false:
| Value | Example |
|---|---|
false | false |
0, -0 | 0, -0 |
"" | empty string |
null | null |
undefined | undefined |
NaN | NaN |
All other values — including any non‑zero number, non‑empty string, array, object, function — are truthy.
Quick code demonstration
if (0) console.log("truthy"); // never runs
if ("hello") console.log("truthy"); // runs
if (null) console.log("truthy"); // never runs
if ([]) console.log("truthy"); // runs (array is truthy)
Practical benefit: simplified conditions
Instead of writing verbose checks like:
if (email !== "" && email !== null && email !== undefined) { ... }
you can write:
if (email) { ... }
The if (email) condition is false when email is "", null, or undefined — exactly the cases you want to reject.
Worked example: Email form validation
let email = prompt("Enter your email:");
if (email) {
alert("Thank you");
} else {
alert("Please enter email. It is mandatory.");
}
If the user presses Cancel (null) or leaves it empty (""), the condition fails and the else block runs.
Exam tip: A common mistake is assuming
if ("false")is false. It is truthy because it's a non‑empty string. Only the booleanfalseis falsy. Also,if ([])is truthy — empty arrays are objects, which are truthy.
Key takeaways
- Truthiness lets any value act as a boolean in conditions.
- Falsy values:
false,0,"",null,undefined,NaN. - Use truthy checks to write cleaner conditions (
if (age)instead ofif (age !== 0 && age !== null ...)). - Beware:
"0","false",[],{}are all truthy. - Understanding truthiness prevents bugs when validating user input.
Array Basics
Arrays solve the problem of managing collections of data. Instead of dozens of individual variables (song1, song2, …), one array holds all items in an ordered list.
Declaration – use square brackets []:
let playlist = []; // empty array
let fruits = ['banana', 'apple', 'peach']; // initialised with three strings
Key fact: typeof an array returns "object" – arrays are a special kind of object in JavaScript.
What can an array hold?
- Any data type — numbers, strings, booleans,
null,NaN, even other arrays. - Mixed types in the same array are allowed (JavaScript is dynamically typed).
let mixed = [1, 11.4, "asd", true, NaN, null, [1, 2, 3]];
// mixed.length is 8; the nested array counts as one element
Nested arrays (arrays inside arrays) are useful for complex data like matrices or grouped records.
The length property
array.length returns the count of elements, not the highest index.
Example: fruits.length → 3 even though indices go 0,1,2.
Exam tip:
lengthis a property, not a method — no parentheses. Use it to loop or to add an element at the end viaarray[array.length] = "new".
Key takeaways – Array creation & properties
- Arrays store multiple values under one variable, making code cleaner.
- Declare with
[]; empty or initialised with comma-separated values. typeof array→"object".- Arrays can mix types, including nested arrays.
lengthgives the number of elements, not the last index.
Indexing and Mutability
Arrays are zero-indexed. Access elements with square brackets:
console.log(fruits[0]); // "banana"
console.log(fruits[2]); // "peach"
console.log(fruits[99]); // undefined — no error
Arrays are mutable – you can change an element directly:
fruits[0] = "mango"; // changes first element
fruits[3] = "mango"; // adds a new element at index 3
fruits[10] = "tomato"; // adds at index 10; indices 4–9 become empty slots (undefined)
Exam tip: Mutability is a key difference from strings. Strings are immutable –
str[0] = "B"does nothing; arrays change in place.
Sparse arrays – assigning to an index far beyond length creates empty slots (filled with undefined but not actual undefined values). The array’s length jumps to that index + 1.
let fruits = ['banana','apple','peach'];
fruits[10] = 'tomato';
// fruits[4..9] are empty; fruits.length becomes 11
Manual addition to the end (cumbersome)
fruits[fruits.length] = 'strawberry'; // works but verbose
Array Methods – Adding and Removing Elements
JavaScript provides built-in methods that handle indexing automatically. Most modify the original array (in place), unlike string methods that return a new string.
| Method | Operation | Location | Return value | Mutates? |
|---|---|---|---|---|
push(elem1, elem2, ...) | Add one or more | End | New array length (implied) | Yes |
pop() | Remove one | End | Removed element | Yes |
unshift(elem1, elem2, ...) | Add one or more | Start | New array length | Yes |
shift() | Remove one | Start | Removed element | Yes |
push and pop – work at the end
let fruits = ['tomato', 'green strawberry'];
fruits.push('kiwi', 'blueberry'); // adds two elements
console.log(fruits); // ['tomato','green strawberry','kiwi','blueberry']
let popped = fruits.pop(); // removes 'blueberry'
console.log(popped); // 'blueberry'
console.log(fruits); // ['tomato','green strawberry','kiwi']
shift and unshift – work at the start
Analogy (queue):
shiftremoves the first person; everyone shifts forward.unshiftadds a “celebrity” to the front; everyone shifts back.
let queue = [1,2,3,4,5,6];
let first = queue.shift(); // removes 1, returns 1
console.log(queue); // [2,3,4,5,6]
queue.unshift('govind', 'friend'); // adds two to front
console.log(queue); // ['govind','friend',2,3,4,5,6]
Exam tip:
shiftandunshifthave confusing names. Remember: shift = remove first → everyone shifts forward; unshift = add first → everyone un-shifts (moves back). Practice with small arrays.
Key difference from strings
let str = "cat";
str[0] = "b"; // fails silently – str remains "cat"
str.toUpperCase(); // returns "CAT" but str unchanged
let arr = [1,2,3];
arr.push(4); // arr becomes [1,2,3,4] – modified in place
- Strings: methods return a new string; original unchanged.
- Arrays (most mutator methods): modify the array directly.
Key takeaways – Indexing & methods
- Access/modify elements with
arr[index]. - Arrays are mutable; assigning beyond
lengthcreates empty slots. push/popoperate at the end;unshift/shiftat the start.- All four methods mutate the original array.
popandshiftreturn the removed element;pushandunshiftreturn the new length (commonly used but not explicitly required).- Always check MDN for full details on array methods.
More Array Methods
Array methods are built-in functions that let you manipulate, query, and transform arrays efficiently. The key difference between them is whether they mutate (modify) the original array or leave it unchanged. Most methods return a new array or a single value instead.
concat – Combine arrays
concat() merges two or more arrays into a new array. It does not change the original arrays.
const veggies = ['tomato', 'cucumber', 'carrot'];
const fruits = ['apple', 'banana'];
const combined = veggies.concat(fruits);
// combined → ['tomato', 'cucumber', 'carrot', 'apple', 'banana']
// veggies is unchanged
Also accepts multiple arrays: veggies.concat(fruits, playlist).
includes – Check for existence
includes() returns a Boolean – true if the element exists in the array, false otherwise. It performs an exact match and does not modify the array.
veggies.includes('cucumber'); // true
veggies.includes('car'); // false (partial match not allowed)
indexOf – Find the first index
indexOf() returns the first index of a given element, or -1 if not found. Works like the string version. Does not mutate.
veggies.indexOf('carrot'); // 2
veggies.indexOf('car'); // -1
join – Make a string from an array
join() concatenates all elements into a string, separated by a given separator (default is comma). The array itself is unchanged.
veggies.join(); // "tomato,cucumber,carrot"
veggies.join(' - '); // "tomato - cucumber - carrot"
veggies.join(' - govind - '); // "tomato - govind - cucumber - govind - carrot"
reverse – Flip the order
reverse() reverses the order of elements in place – the original array is mutated.
console.log(veggies); // ['tomato', 'cucumber', 'carrot']
veggies.reverse();
console.log(veggies); // ['carrot', 'cucumber', 'tomato']
slice – Extract a portion
slice(start, end) returns a shallow copy of a portion of the array from start (inclusive) to end (exclusive). Negative indexes count from the end. Original array is not modified.
const arr = ['tomato', 'cucumber', 'carrot', 'enter sandman'];
arr.slice(1, 4); // ['cucumber', 'carrot', 'enter sandman'] (index 1 to 3)
arr.slice(1); // ['cucumber', 'carrot', 'enter sandman'] (from index 1 to end)
arr.slice(-2); // ['carrot', 'enter sandman'] (last two elements)
splice – Add, remove, or replace
splice(start, deleteCount, item1, item2, ...) mutates the array. It removes deleteCount elements starting at index start, then optionally inserts any provided items at that position.
deleteCount | Items provided | Effect |
|---|---|---|
| > 0 | none | Remove that many elements |
| 0 | yes | Insert items without removing anything |
| > 0 | yes | Replace removed elements with the items |
Examples
let arr = veggies.concat(fruits, playlist); // large test array
// Remove 2 items from index 1
arr.splice(1, 2); // removes 'cucumber' and 'carrot'
// Remove 2 from index 1 and insert 'govind'
arr.splice(1, 2, 'govind');
// Insert without removal: arr.splice(1, 0, 'govind', 'raj', veggies);
Exam tip: The fastest way to tell if a method mutates: read MDN. Common mutating methods:
reverse,splice,push,pop,shift,unshift. Non-mutating:concat,includes,indexOf,join,slice,map,filter.
Quick reference table
| Method | Mutates? | Returns | Purpose |
|---|---|---|---|
concat | No | New array | Combine arrays |
includes | No | Boolean | Check existence |
indexOf | No | Number (index or -1) | Find first index |
join | No | String | Create string from array |
reverse | Yes | The mutated array itself | Reverse order |
slice | No | New array (shallow copy) | Extract a portion |
splice | Yes | Array of removed elements | Add/remove/replace in place |
Key takeaways
concat,includes,indexOf,join,slicedo not modify the original array.reverseandsplicemutate the original array.spliceis the most flexible: you can delete, insert, or replace in one call.- The
slicemethod behaves like the stringslice– same syntax, zero-based, negative indexes work. - Always verify method behaviour on MDN; memorisation is not required – practice builds familiarity.
Arrays as Reference Types
JavaScript arrays are reference types, not primitive values. A variable holding an array stores a memory address (a reference) to where the array’s data lives—not the data itself. This has two critical consequences: value-based comparison fails, and assignment creates aliases.
Arrays Are Not Equitable by Value
Two arrays with identical elements are different objects in memory. Using == or === compares their references, not their contents.
const fruits1 = ['apple', 'banana'];
const fruits2 = ['apple', 'banana'];
console.log(fruits1 == fruits2); // false
console.log(fruits1 === fruits2); // false
To compare actual array contents, you must iterate element-by-element or use a utility (e.g., every() with index matching). Direct equality always returns false for distinct arrays.
Assignment Creates a Shared Reference
When you assign an array to another variable, the new variable points to the same memory location. Mutating the array through either variable changes the shared data.
const a1 = [1, 2];
const a2 = a1; // a2 references same array as a1
a1[1] = 5; // mutate the shared array
console.log(a1, a2); // both are [1, 5]
This contrasts with primitive values (numbers, strings), where assignment copies the value:
| Data type | Operation | Outcome |
|---|---|---|
| Primitive | let x=1; let y=x; x=2; | y remains 1 |
| Array (reference) | let a=[1,2]; let b=a; a[0]=5; | b also sees [5,2] |
How to break the reference – create a true copy:
- Assign a new array literal:
a2 = [1, 2]; - Use
.slice()(returns a shallow copy):a2 = a1.slice();
After a true copy, mutations to the original do not affect the copy.
let a1 = [1, 2];
let a2 = a1.slice();
a1[0] = 10;
console.log(a1, a2); // [10, 2] and [1, 2]
Exam tip: Any direct assignment
arr2 = arr1makes both variables reference the same array. Mutations through either one affect the other. To guard against unintended side effects, always copy with.slice()or the spread operator.
Key takeaways
- Arrays are stored as references;
==/===compare memory locations, not contents. - Two different arrays with identical elements are never
===. - Assigning an array to a new variable creates an alias, not a copy.
- Mutating the array through any alias changes the shared data.
- Use
.slice()(or spread[...arr]) to create a shallow copy and break the alias.
Multidimensional Arrays (Nested Arrays)
A multidimensional array is an array whose elements are themselves arrays. Useful for matrices, grids, and tabular data.
Example – 3×3 matrix (2D array):
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
Accessing elements:
matrix[0]→ first row:[1, 2, 3]matrix[0][1]→ first row, second column:2- Use successive bracket notation:
[row][col]for 2D.
Higher dimensions – adding another level of nesting (array inside an array inside an array) creates a 3D structure.
Key takeaways
- Nested arrays create multidimensional structures (2D, 3D, etc.).
- Access elements with multiple bracket indices:
arr[i][j][k]. - Common uses: matrix operations, game boards, spreadsheets.
Overall Key Takeaways
- Arrays are reference types – never compare with
==/===to check content equality. - Assigning an array copies the reference, not the data; mutations propagate.
- Create independent copies with
.slice()or spread syntax. - Multidimensional arrays (arrays of arrays) enable row–column data structures; index with multiple brackets.
JavaScript Objects
Objects in JavaScript are collections of key-value pairs. They store multiple related values, each labeled with a meaningful key (or property name). Think of an object as a labeled filing cabinet: you access a value by its label, not by a numeric index (as in arrays). Objects are fundamental for representing complex, structured data.
Syntax
An object literal is defined with curly braces {}. Inside, keys and values are separated by a colon :, and pairs are comma-separated:
let person = {
name: "Govind", // key: "name", value: "Govind"
age: 120, // key: "age", value: 120
isStudent: false, // key: "isStudent", value: false
classes: ["web development", "Excel"], // value can be an array
address: "Bannerghatta, Bangalore"
};
Keys are implicitly converted to strings (even if you omit quotes). The convention is to use camelCase keys that follow variable naming rules.
Properties
Each key-value pair is called a property. You have already used properties on built-ins (e.g., "hello".length). Objects let you define your own.
Values can be any data type:
- string, number, boolean
- array
- nested object (another object)
- function (covered in a later module)
Accessing Properties
Two ways to read a property’s value:
| Notation | Syntax | Example | Notes |
|---|---|---|---|
| Dot notation | object.key | person.name → "Govind" | Key must be a valid identifier (no spaces, no numbers at start) |
| Bracket notation | object["key"] | person["age"] → 120 | Key is always a string (even if you write 123, it becomes "123") |
Use dot notation for known, simple keys; bracket notation when the key is dynamic or contains characters that break dot syntax.
Dynamic keys with bracket notation
Bracket notation accepts a variable whose value is a string key:
let searchKey = "name";
console.log(person[searchKey]); // "Govind"
searchKey = "123";
console.log(person[123]); // Access key "123", works because key is auto-converted
Exam tip: Bracket notation is essential for computed or runtime‑determined keys. Dot notation is safer for hard‑coded keys, but bracket notation is more flexible — know both.
Modifying and Adding Properties
You can change an existing property or add a new one by simple assignment:
person.name = "Simran"; // dot notation – update
person.isStudent = true; // update
person.ethnicity = "Indian"; // add new property (dot)
person["fatherName"] = "Shah Rukh Khan"; // add new property (bracket)
Properties that don’t exist are created on the fly.
Nested Objects
A property’s value can itself be an object, enabling deep data structures:
let person = {
name: "Govind",
address: {
city: "Bangalore",
street: "Bannerghatta",
pinCode: 123456
}
};
console.log(person.address.city); // "Bangalore"
console.log(person["address"]["pinCode"]); // 123456
Access nested properties by chaining dot or bracket notation.
Use Cases
- User profiles (username, email, password)
- Product details (name, price, available)
- Application settings (theme, volume)
- Every HTML element as a DOM object (next module)
- The entire
documentobject is a JavaScript object
Objects make code more readable and data more organised than separate variables.
Key takeaways
- Objects are key-value pairs inside
{}; keys are always strings. - Dot notation is concise for known, valid identifiers; bracket notation handles dynamic or problematic keys.
- Properties can be added or updated by assignment on the fly.
- Values can be any type, including nested objects and arrays.
- Bracket notation requires the key as a string (or variable holding a string).
- Use objects to bundle related data instead of many independent variables.
Loops in JavaScript
Loops let you repeat actions without duplicating code. Instead of writing hundreds of lines to display each comment or product, one loop iterates over the collection and handles each item dynamically.
Why loops matter
- Process lists of data (comments, products, search results).
- Display many items from arrays or objects.
- Perform repetitive calculations.
- Keep code clean, concise, and adaptable.
The for loop – the most common loop
The for loop runs a block of code a specific number of times. Its syntax has three parts inside parentheses, separated by semicolons:
for (initialization; condition; increment) {
// body – code to repeat
}
| Part | Purpose | Example |
|---|---|---|
| Initialization | Declare and set a loop variable (often i). Runs once before the loop starts. | let i = 0 |
| Condition | Checked before each iteration. If true, the body runs; if false, the loop stops. | i <= 10 |
| Increment | Updates the loop variable after each iteration. | i++ (adds 1) |
Order of execution
Worked example: Print numbers 0 to 10
for (let i = 0; i <= 10; i++) {
console.log(i);
}
How it runs (step‑by‑step):
i = 0→ check0 <= 10→ true → print0→ibecomes1i = 1→ check1 <= 10→ true → print1→ibecomes2- … continues until
i = 10→ print10→ibecomes11 i = 11→ check11 <= 10→ false → exit
Output: 0 1 2 3 4 5 6 7 8 9 10 (11 numbers, because i <= 10 includes 10).
Iterating over an array with a for loop
Given an array playlist = ["Enter Sandman", "Nothing Else Matters", "Fade to Black", "Unforgiven"], we can print each element:
for (let i = 0; i < playlist.length; i++) {
console.log(playlist[i]);
}
istarts at0(first index).- Condition uses
playlist.length(here 4) → loops whilei < 4→ indices 0,1,2,3. - Prints each song.
Number the songs (1‑based)
for (let i = 0; i < playlist.length; i++) {
console.log(`Song ${i + 1} is ${playlist[i]}`);
}
i + 1is just for display; the actual loop variableiremains unchanged.
Variations of the for loop
1. Different step sizes
| Increment expression | Effect | Example output (0 to 10, step 2) |
|---|---|---|
i += 2 | Skips every other number | 0 2 4 6 8 10 |
i *= 9 | Multiplies each step | 1 9 81 (if start at 1) |
2. External counter (initialization outside)
let i = 1;
for (; i <= 100; i += 9) {
console.log(i);
}
3. Increment inside the body
for (let i = 1; i <= 100; ) {
console.log(i);
i += 9;
}
All variations work as long as the loop variable is updated and the condition eventually becomes false.
Infinite loops – the critical trap
An infinite loop occurs when the condition never becomes false. The program freezes or crashes.
Dangerous examples
// Multiply by 9 starting from 0
for (let i = 0; i <= 100; i *= 9) {
console.log(i); // i stays 0 forever
}
// Condition always true
for (let i = 0; i >= 0; i++) {
console.log(i); // i keeps increasing, condition never false
}
Exam tip: Always ensure that something inside the loop changes the loop variable so that the condition will eventually be
false. The most common mistake is an increment that doesn’t actually change the value (e.g.,i *= 9wheni = 0) or a condition that can never be satisfied (e.g.,i >= 0withi++).
Key takeaways
forloops repeat code a fixed number of times using initialization, condition, and increment.- The condition is checked before each iteration; the increment runs after the body.
- Use
array.lengthas the upper bound when iterating over arrays. - Increment can be any expression (
+=2,*=9, etc.) but must eventually make the condition false. - An infinite loop crashes the application – always verify that the loop will terminate.
- The
forloop is the foundation; other loops (while,for…in,for…of) are covered in later videos.
Nested Loops
A nested loop places one loop inside another. The inner loop runs through all its iterations for every single iteration of the outer loop. This structure is essential for processing multidimensional data – for example, a 2D grid or an array of arrays.
How it works (basic example)
for (let i = 0; i < 2; i++) {
console.log("outer loop", i);
for (let j = 0; j < 3; j++) {
console.log("inner loop", j);
}
}
Output:
outer loop 0
inner loop 0
inner loop 1
inner loop 2
outer loop 1
inner loop 0
inner loop 1
inner loop 2
The outer loop runs twice, and for each of those two runs the inner loop runs three times – total 6 inner iterations.
Traversing a nested array (traditional approach)
Given a nested (2D) array, you need one loop for the outer array and another loop for each inner array.
const nestedArray = [[1, 2], [3, 4, 5], [6, 7]];
for (let i = 0; i < nestedArray.length; i++) {
console.log("Outer array:", nestedArray[i]);
for (let j = 0; j < nestedArray[i].length; j++) {
console.log("Inner element:", nestedArray[i][j]);
}
}
The outer loop index i selects each sub‑array; the inner loop index j walks through the elements of that sub‑array.
for...of – modern iteration for arrays and strings
for...of directly gives you each value of an iterable (arrays, strings, Maps, Sets, etc.). No indexing needed – it’s more readable and less error‑prone.
Array example
for (const outerArray of nestedArray) { // outerArray is each sub‑array
console.log("Outer array:", outerArray);
for (const element of outerArray) { // element is each value inside
console.log("Inner element:", element);
}
}
Same output as the nested‑loop version above, but simpler.
String example (strings are iterable)
for (const char of "Hello") {
console.log(char); // prints H, e, l, l, o
}
Exam tip:
for...ofworks on any iterable, but not on plain objects. Tryingfor (const x of person)will throw a TypeError.
for...in – object keys (use with caution)
for...in iterates over the keys (property names) of an object. You can then access values via bracket notation.
const person = { name: "Alice", age: 25, student: true };
for (const key in person) {
console.log(key, person[key]); // name Alice, age 25, student true
}
Drawbacks:
- Confusing name – many languages use
infor arrays, so it’s easy to mix up withfor...of. - It also iterates over inherited enumerable properties (unless filtered).
- Not recommended for arrays; use
for...ofinstead.
Better alternative: Object.keys, Object.values, Object.entries
Instead of for...in, use these static methods that return arrays – then iterate with for...of.
| Method | Returns | Example usage |
|---|---|---|
Object.keys(obj) | Array of keys | for (const k of Object.keys(person)) |
Object.values(obj) | Array of values | for (const v of Object.values(person)) |
Object.entries(obj) | Array of [key, value] pairs | for (const [k, v] of Object.entries(person)) |
Example (preferred approach):
const person = { name: "Alice", age: 25 };
// Keys only
for (const key of Object.keys(person)) {
console.log(key); // name, age
}
// Values only
for (const val of Object.values(person)) {
console.log(val); // Alice, 25
}
// Key-value pairs
for (const [key, val] of Object.entries(person)) {
console.log(key, val); // name Alice, age 25
}
This pattern is explicit, works with any array‑iteration method, and avoids the confusion of for...in.
Summary of loop choices
Key takeaways
- Nested loops: outer loop controls rows, inner loop controls columns (or sub‑elements).
for...ofis the cleanest way to iterate arrays, strings, and other iterables.for...initerates object keys but is error‑prone; preferObject.keys()/Object.values()/Object.entries().- Use traditional
for (let i = 0; i < arr.length; i++)when you need the index or break early. - For objects, always convert to an array first using
Object.*methods, then usefor...of.
Exam tip: Interviewers love asking why
for...inon an array is bad – it includes inherited properties and key order isn’t guaranteed. Stick withfor...offor array values.
Functions in JavaScript
A function is a reusable block of code that performs a specific task. Instead of writing the same logic over and over, you define it once and call it whenever needed. This follows the DRY (Don't Repeat Yourself) principle, making code more readable, modular, and testable.
Defining vs Calling
- Defining a function stores it in memory without executing the code.
- Calling (or invoking) a function runs the defined code.
// Defining
function greet() {
console.log("Hello world");
}
// Calling
greet(); // logs "Hello world"
If you only reference the function name without parentheses (e.g., greet), JavaScript just tells you it's a function — it doesn't run it.
Parameters and Arguments
Functions can accept inputs to work with. The placeholder in the definition is a parameter; the actual value passed during the call is an argument.
function greet(name, age) {
console.log(`Hello world ${name}. Wow, you are ${age} years old.`);
}
greet("Govind", 24); // "Hello world Govind. Wow, you are 24 years old."
| Term | Definition | Example |
|---|---|---|
| Parameter | Variable defined in the function declaration | name, age |
| Argument | Actual value supplied when calling the function | "Govind", 24 |
If you call a function without providing an argument for a defined parameter, that parameter becomes undefined — the function still runs but with undefined in place.
Hoisting
JavaScript hoists function declarations to the top of their scope, so you can call a function before its definition appears in the code. However, relying on this is discouraged — always define before calling for clarity and easier debugging.
Worked Example: Generating a Random Number Repeatedly
Instead of writing console.log(Math.random()) multiple times, wrap it in a function:
function printRandom() {
console.log(Math.random());
}
printRandom(); // logs a random number
printRandom(); // logs another random number
printRandom(); // logs another random number
Now you have a single block you can call from anywhere.
Exam tip: Hoisting only applies to function declarations (the
functionkeyword form), not to function expressions (e.g.,const f = function() {}). Know the difference — it’s a common trick question.
Key takeaways
- A function is a reusable block of code defined with the
functionkeyword. - Defining stores the code; calling (with
()) executes it. - Parameters are placeholders in the definition; arguments are the actual values passed.
- Missing arguments become
undefined— the function still runs. - Hoisting allows calling before definition, but good practice defines first.
Advanced Concepts in Functions
Functions in JavaScript can be treated as first-class citizens: they can be assigned to variables, passed as arguments, and returned from other functions. This flexibility enables powerful patterns like callbacks, factory functions, and recursion.
Assigning Functions to Variables
A function can be referenced by a variable without being executed. The variable can then be used to call the function.
function add(a, b) { return a + b; }
let addition = add; // No parentheses – we assign the function itself
console.log(addition(1, 2)); // 3
Anonymous functions — functions without a name — can be created and directly assigned to a variable. A function statement without a name is invalid, but when used in an assignment it becomes valid.
let addition = function(a, b) { return a + b; };
addition(1, 2); // 3
Passing Functions as Arguments (Callbacks)
Because functions are first-class, they can be passed into other functions as arguments. This pattern is called a callback and enables reusable, dynamic logic.
Worked Example: executeXTimes
function randomNumber() {
console.log(Math.floor(Math.random() * 100));
}
function executeXTimes(fn, count) {
let i = 0;
while (i < count) {
fn(); // fn is the function passed in
i++;
}
}
executeXTimes(randomNumber, 5); // logs 5 random numbers
randomNumberis passed without parentheses — we pass the reference, not the result.- Inside
executeXTimes,fnis called usingfn().
Returning Functions (Factory Functions)
A function can return another function. This allows creating specialized functions on the fly — a factory function.
function multiplierFactory(multiplier) {
return function(value) {
return value * multiplier;
};
}
const double = multiplierFactory(2);
const triple = multiplierFactory(3);
console.log(double(10)); // 20
console.log(triple(10)); // 30
- The outer function captures the
multiplierargument via closure. - The returned inner function uses that captured value whenever called.
Recursion
Recursion is when a function calls itself. It is useful for traversing nested structures where the depth is unknown (e.g., nested arrays, trees).
Worked Example: Printing a Nested Array
function printNestedArray(arr) {
for (let item of arr) {
if (Array.isArray(item)) {
printNestedArray(item); // recursive call
} else {
console.log(item);
}
}
}
let nestedArray = [
[2.1, 2.2, 2.3],
3, 4,
[[5.11, 5.12], [5.21, 5.22]],
6, 7, 8, 9
];
printNestedArray(nestedArray);
// Output: 2.1, 2.2, 2.3, 3, 4, 5.11, 5.12, 5.21, 5.22, 6, 7, 8, 9
- Base condition: when an item is not an array, print it and stop recursing that branch.
- Without a base condition, infinite recursion would crash the program.
Exam tip: Always ensure a recursive function has a base case that terminates the calls.
Object Methods
Methods are functions stored as properties of an object. They can access and modify the object’s data using the this keyword.
Defining a Method – Two Syntaxes
-
Property + anonymous function:
let person = { name: "Govind", age: 25, speak: function() { return `My name is ${this.name}`; } }; -
Shorthand syntax (more modern):
let person = { name: "Govind", age: 25, greet() { return `Hi, my name is ${this.name}, age ${this.age}`; } };
- Call a method with parentheses:
person.speak()→"My name is Govind" thisinside the method refers to the object the method belongs to. Changingperson.nameupdates the output.- All methods are functions, but not all functions are methods — methods are tied to a specific object.
Key Takeaways
- Functions can be assigned to variables, making them first-class citizens.
- Anonymous functions work when assigned, but not as standalone statements.
- Callbacks (passing functions as arguments) enable reusable, dynamic code.
- Factory functions return specialized functions via closures.
- Recursion solves problems with nested structures; always include a base condition.
- Methods are functions inside objects; use
thisto reference the object’s properties.