Term 2 · Module 6 of 8

Basics of Javascript

Website Development

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

  1. 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+Enter to write multiple lines before executing.
  2. 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.
  3. In HTML files (later modules) – JavaScript is added via <script> tags in a .html file, run with Live Server.
ToolBest forNotes
ConsoleQuick tests, single expressionsNot saved; accidental Enter executes
SnippetsMulti‑line code, saved snippetsSaved in browser, easy to rerun
HTML <script>Full web pagesUsed in later modules for DOM

First command: alert()

alert("Hello");
alert("Hi");
alert("Hello boss");
  • alert – a built‑in keyword that calls a function (technically window.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 the window object, but you can write just alert(). 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: keyword alert, 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., \n for 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: typeof is an operator, not a function. Common mistake: writing typeof(x) — while it works, the correct form is typeof 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.
  • typeof is 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 – true or false.
  • typeof – operator to return the type as a string.
  • Same literal (e.g., 25 vs "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:

KeywordUse caseCan reassign?
letModern, value may changeYes
varOlder style, similar to let but different scopeYes
constValue must stay constantNo (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 (city not x).
  • Use let by default in modern code; use const when the value is fixed.

Assignment and Reassignment

  • Declaration creates the variable (using let, var, or const).
  • 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, or const.
  • let and var allow reassignment; const does 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 null if 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), not 8.

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

RuleWhy
No special characters (@,#,%)Cause syntax errors
No spaceslet user age → unexpected number
No JavaScript reserved wordslet, const, function, if, etc.
No starting with _ (convention)Reserved for internal/protected properties
No starting with a digitIllegal 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 totalItems instead of let x.
  • Concise – avoid overly long names like totalNumberOfElementsInCart; use totalItems.
  • 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

  1. Store the value of cup1 into a third variable cup3.
  2. Assign cup1 the value of cup2.
  3. Assign cup2 the value of cup3.
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 into cup3. Changing cup1 later (e.g., cup1 = "juice") does not affect cup3 – 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:

CharacterIndex
H0
e1
l2
l3
o4

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:

ExpressionResultExplanation
"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.
  • .length gives 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, ...)
  • string can 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

MethodWhat it doesReturns
.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: .indexOf returns -1 when 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 -1 if substring is 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 start given: returns from that index to the end.
  • If start and end given: returns from start up to but not including end.
  • 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 count times – 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.
  • .indexOf returns -1 when not found.
  • .slice(start, end) does not include the character at end.
  • .replace only 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.`);
FeatureOld concatenationTemplate literal
Quote style' or "` (backtick)
Variable insertion"..." + var + "..."`${var}`
Expression insertionMust pre‑compute`${2 + 4}` → "6"
Multi‑line stringsNeed \nJust 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.

ConceptWho sets it?Meaningtypeof
undefinedAutomatically by JavaScriptA variable has been declared but not assigned; a missing property."undefined"
nullExplicitly 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: null is an object type in JavaScript – a historical mistake. undefined is its own type. They are loosely equal (null == undefined → true) but strictly not equal (null === undefined → false).

When to use each

  • Use null when you want to explicitly say “no value here” (e.g., future assignment, cleared data).
  • Let JavaScript give you undefined when something is missing – you do not usually assign undefined yourself.

Key takeaways

  • null is programmer‑set; undefined is JS‑set.
  • typeof null → "object"; typeof undefined → "undefined".
  • Both mean “nothing”, but context matters.
  • Loosely equal (==), but strict equality (===) is false.

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

OperatorNameExample (x=10, y=20)Result
+Additionx + y30
-Subtractionx - y-10
*Multiplicationx * 550
/Divisiony / 54
**Exponentiation (power)x ** 2100
%Modulus (remainder)10 % 31

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, then 5+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.

OperatorEquivalent toExample (starting x=10)
x += 4x = x + 4x → 14
x -= 5x = x - 5x → 5
x *= 2x = x * 2x → 20
x /= 2x = x / 2x → 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 === 0 tests evenness.
  • Order: Parentheses → Exponents → MD → AS. Use parentheses for clarity.
  • ++ and -- increment/decrement by 1 on variables.
  • Compound assignment (+=, -=, *=, /=) shortens x = 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)

PropertyValue
Math.PI3.141592653589793

Methods

Rounding

MethodBehaviourExampleResult
Math.round(x)Rounds to nearest integerMath.round(3.43) → 3; Math.round(5.55) → 6
Math.floor(x)Rounds down to lower integerMath.floor(5.9999) → 5
Math.ceil(x)Rounds up to higher integerMath.ceil(3.43) → 4

Other Common Methods

MethodPurposeExampleResult
Math.abs(x)Absolute value (removes sign)Math.abs(-1)1
Math.sqrt(x)Square rootMath.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:

  1. Math.random() → 0.0 to 0.999...
  2. Multiply by 10 → 0.0 to 9.999...
  3. Math.floor() → integer 0 to 9
  4. Add 1 → integer 1 to 10

Exam tip: to get a random integer in [min, max], the general formula is Math.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.PI gives π.
  • Three rounding methods: round (nearest), floor (down), ceil (up).
  • abs, sqrt, pow are standard math helpers.
  • Math.random() returns [0,1); use Math.floor(Math.random() * N) + 1 for 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

OperatorMeaningExampleResult
<Less than3 < 4true
>Greater than3 > 4false
<=Less than or equal to10 <= 10true
>=Greater than or equal to9 >= 10false
==Loose equality (type coercion allowed)10 == '10'true
===Strict equality (type must also match)10 === '10'false
!=Loose inequality10 != '10'false
!==Strict inequality10 !== '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 (!).

ABA && BA || B!A
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue
  • && (AND) → true only when both sides are true.
  • || (OR) → true when at least one side is true.
  • ! (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
}
  • if is a keyword; condition must be a boolean (true / false).
  • Curly braces {} form a block; no semicolon after the closing brace.
  • Statements before and after the if block 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 condition false, second true → "Kind of hot day".
  • 100 → all three else if conditions false → "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

StructureBehavior
if…else if…elseOnly one block runs (first true condition).
Multiple standalone ifEach 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 if checks age eligibility first.
  • Only if age >= 18 does the inner if check 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 if chain, order matters. When overlapping ranges exist (e.g., marks > 95 and marks > 80), the first true condition executes and the rest are ignored. Always test edge cases like marks = 96 where both could be true.

Key Takeaways

  • if runs code only when its condition is true.
  • else if adds additional conditions; else is the default catch‑all.
  • In a chain, only one block executes — the first true one.
  • Separate if statements are independent and may both run.
  • Nesting places an if inside another if to 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

BenefitDrawback
Handles dependent conditions cleanlyReadability suffers as nesting depth increases
Avoids repeating outer checksDebugging becomes harder
Matches natural decision hierarchiesOveruse 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:

ValueExample
falsefalse
0, -00, -0
""empty string
nullnull
undefinedundefined
NaNNaN

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 boolean false is 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 of if (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: length is a property, not a method — no parentheses. Use it to loop or to add an element at the end via array[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.
  • length gives 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.

MethodOperationLocationReturn valueMutates?
push(elem1, elem2, ...)Add one or moreEndNew array length (implied)Yes
pop()Remove oneEndRemoved elementYes
unshift(elem1, elem2, ...)Add one or moreStartNew array lengthYes
shift()Remove oneStartRemoved elementYes

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):

  • shift removes the first person; everyone shifts forward.
  • unshift adds 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: shift and unshift have 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 length creates empty slots.
  • push / pop operate at the end; unshift / shift at the start.
  • All four methods mutate the original array.
  • pop and shift return the removed element; push and unshift return 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.

deleteCountItems providedEffect
> 0noneRemove that many elements
0yesInsert items without removing anything
> 0yesReplace 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

MethodMutates?ReturnsPurpose
concatNoNew arrayCombine arrays
includesNoBooleanCheck existence
indexOfNoNumber (index or -1)Find first index
joinNoStringCreate string from array
reverseYesThe mutated array itselfReverse order
sliceNoNew array (shallow copy)Extract a portion
spliceYesArray of removed elementsAdd/remove/replace in place

Key takeaways

  • concat, includes, indexOf, join, slice do not modify the original array.
  • reverse and splice mutate the original array.
  • splice is the most flexible: you can delete, insert, or replace in one call.
  • The slice method behaves like the string slice – 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 typeOperationOutcome
Primitivelet 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 = arr1 makes 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:

NotationSyntaxExampleNotes
Dot notationobject.keyperson.name → "Govind"Key must be a valid identifier (no spaces, no numbers at start)
Bracket notationobject["key"]person["age"] → 120Key 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 document object 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
}
PartPurposeExample
InitializationDeclare and set a loop variable (often i). Runs once before the loop starts.let i = 0
ConditionChecked before each iteration. If true, the body runs; if false, the loop stops.i <= 10
IncrementUpdates 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):

  1. i = 0 → check 0 <= 10 → true → print 0 → i becomes 1
  2. i = 1 → check 1 <= 10 → true → print 1 → i becomes 2
  3. … continues until i = 10 → print 10 → i becomes 11
  4. i = 11 → check 11 <= 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]);
}
  • i starts at 0 (first index).
  • Condition uses playlist.length (here 4) → loops while i < 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 + 1 is just for display; the actual loop variable i remains unchanged.

Variations of the for loop

1. Different step sizes

Increment expressionEffectExample output (0 to 10, step 2)
i += 2Skips every other number0 2 4 6 8 10
i *= 9Multiplies each step1 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 *= 9 when i = 0) or a condition that can never be satisfied (e.g., i >= 0 with i++).

Key takeaways

  • for loops 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.length as 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 for loop 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...of works on any iterable, but not on plain objects. Trying for (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 in for arrays, so it’s easy to mix up with for...of.
  • It also iterates over inherited enumerable properties (unless filtered).
  • Not recommended for arrays; use for...of instead.

Better alternative: Object.keys, Object.values, Object.entries

Instead of for...in, use these static methods that return arrays – then iterate with for...of.

MethodReturnsExample usage
Object.keys(obj)Array of keysfor (const k of Object.keys(person))
Object.values(obj)Array of valuesfor (const v of Object.values(person))
Object.entries(obj)Array of [key, value] pairsfor (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...of is the cleanest way to iterate arrays, strings, and other iterables.
  • for...in iterates object keys but is error‑prone; prefer Object.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 use for...of.

Exam tip: Interviewers love asking why for...in on an array is bad – it includes inherited properties and key order isn’t guaranteed. Stick with for...of for 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."
TermDefinitionExample
ParameterVariable defined in the function declarationname, age
ArgumentActual 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 function keyword 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 function keyword.
  • 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
  • randomNumber is passed without parentheses — we pass the reference, not the result.
  • Inside executeXTimes, fn is called using fn().

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 multiplier argument 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

  1. Property + anonymous function:

    let person = {
      name: "Govind",
      age: 25,
      speak: function() {
        return `My name is ${this.name}`;
      }
    };
    
  2. 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"
  • this inside the method refers to the object the method belongs to. Changing person.name updates 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 this to reference the object’s properties.