IT237 Web Technology I

Web Technology IUnit 514 min read

JavaScript Basics: Data Types, Variables, Functions & Real-World Logic

Unit 5 of Web Technology I covers JavaScript’s core building blocks—primitive and non-primitive data types, variable declaration, scoping rules, function syntax, and parameter handling—with hands-on validation examples (like eSewa’s form checks) and comparisons to HTML/CSS workflows.

TAKEAWAYS:

  • JavaScript has 8 primitive data types (6 + 2 special cases) and 1 non-primitive type (objects), each with unique storage/behavior.
  • Variables use let, const, or var—scope rules determine accessibility (global vs. block), and hoisting affects execution order.
  • Functions are first-class citizens: they can be passed as arguments, returned from other functions, and assigned to variables.
  • Client-side validation (e.g., phone/email checks) relies on type coercion, regex, and conditional logic—critical for apps like Daraz or Ncell.
  • Debugging tools (Chrome DevTools) let you inspect variables, call stacks, and event listeners in real time.
  • Real-world tie-ins: WhatsApp’s message encryption uses string/boolean logic; YouTube’s “Recommended” system leverages object properties and array methods.

Core Concepts: Data Types in JavaScript

JavaScript’s data types are the foundation of all logic. They determine how values are stored, compared, and manipulated. The language categorizes them into primitive (immutable, stored by value) and non-primitive (mutable, stored by reference).

1. Primitive Data Types

JavaScript has 6 core primitives plus 2 special cases (often treated as primitives for simplicity):

mindmap
  root((JavaScript Data Types))
    Primitive
      Number
        Examples: 42, 3.14, -0.5
        Notes: Includes integers, floats, and special values like `Infinity`, `NaN`
      String
        Examples: "hello", 'Nepal', `` `template ${strings}` ``
        Notes: Immutable sequences of Unicode characters
      Boolean
        Examples: `true`, `false`
        Notes: Used in conditions and logical operations
      Null
        Example: `null`
        Notes: Represents "no value" or "empty"
      Undefined
        Example: `undefined`
        Notes: Default value of uninitialized variables
      Symbol
        Example: `Symbol('id')`
        Notes: Unique and immutable (ES6+), used as object property keys
    Special Cases
      BigInt
        Example: `123n` (note the `n` suffix)
        Notes: Handles integers larger than `Number`’s safe range (2^53 - 1)
      Object
        Example: `{name: "Ramesh", age: 25}`
        Notes: **Non-primitive**; mutable key-value collections

Why it matters:

  • Type coercion happens automatically (e.g., "5" + 2 becomes "52"), but explicit checks (typeof) prevent bugs.
  • null vs. undefined: null is intentional absence; undefined is default or missing.

Type Example Mutable? Storage Key Use Cases
Number 42, 3.14 No 64-bit float Math operations, counters
String "hello" No UTF-16 Text display, user input
Boolean true No 1 bit Conditions (if, loops)
Null null No — Reset variables, API responses
Undefined undefined No — Uninitialized vars, function returns
Symbol Symbol('id') No Unique ID Object property keys (avoid collisions)
BigInt 123n No Arbitrary Cryptography, large IDs
Object {} Yes Reference Complex data (arrays, functions, DOM)

2. Variables: Declaration and Scope

Variables store data temporarily. JavaScript offers three ways to declare them, each with different scoping rules:

stateDiagram-v2
  [*] --> VarDeclared
  VarDeclared --> GlobalScope: if outside function/block
  VarDeclared --> FunctionScope: if inside function (old behavior)
  GlobalScope --> Hoisted: accessible anywhere
  FunctionScope --> Hoisted: accessible in function
  [*] --> LetConstDeclared
  LetConstDeclared --> BlockScope: if inside { }
  BlockScope --> NotHoisted: TDZ (Temporal Dead Zone) until declaration
  BlockScope --> GlobalScope: if outside any block

Key Rules:

  • var:
    • Function-scoped (or global if declared outside functions).
    • Hoisted: Declared at the top of its scope, initialized with undefined.
    • Problem: Redeclaration allowed → bugs in loops.
  • let:
    • Block-scoped (e.g., inside {}).
    • Not hoisted: Throws ReferenceError if accessed before declaration (Temporal Dead Zone).
    • Can be redeclared in a new block.
  • const:
    • Block-scoped.
    • Must be initialized at declaration.
    • Cannot be reassigned (but object/array properties can change).

Worked Example: Scope in Action

function exampleScope() {
  if (true) {
    var x = 10;   // Function-scoped (leaks outside if-block)
    let y = 20;   // Block-scoped (dies here)
    const z = 30;  // Block-scoped
  }
  console.log(x); // 10 (works)
  console.log(y); // ReferenceError (y is not defined)
  console.log(z); // ReferenceError (z is not defined)
}
exampleScope();

Real-World Tie-In: eSewa’s User Session eSewa stores user session data in block-scoped const variables to prevent accidental overwrites. For example:

const userSession = {
  userId: "USER123",
  balance: 5000,
  isLoggedIn: true
};
// Later, when updating balance:
userSession.balance = 4800; // Allowed (property change)
userSession = null;        // TypeError (reassignment blocked)

3. Functions: The Workhorses of JavaScript

Functions are reusable blocks of code that perform tasks. They can:

  • Take parameters (inputs).
  • Return a value (or undefined).
  • Be nested, anonymous, or arrow functions.

Function Syntax

// Declaration (hoisted)
function greet(name) {
  return `Hello, ${name}!`;
}

// Expression (not hoisted)
const greet = function(name) {
  return `Hello, ${name}!`;
};

// Arrow function (ES6+)
const greet = (name) => `Hello, ${name}!`;

Parameters vs. Arguments

  • Parameters: Variables listed in the function definition (e.g., function add(a, b)).
  • Arguments: Actual values passed when calling the function (e.g., add(2, 3)).

Default Parameters (ES6):

function greet(name = "Guest") {
  return `Hello, ${name}!`;
}
greet(); // "Hello, Guest!"

Rest Parameters:

function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}
sum(1, 2, 3); // 6

Caption: Debugging a nested function call in Pathao’s order-processing script.


4. Type Coercion and Explicit Checks

JavaScript automatically converts types in certain operations (e.g., + for strings/numbers). This can lead to unexpected results:

flowchart TD
  A["Operation: '5' + 2"] --> B["Step 1: String Coercion"]
  B --> C["5" + "2" = "52"]
  D["Operation: 5 == '5'"] --> E["Step 1: String Coercion"]
  E --> F["Step 2: Number Comparison"]
  F --> G["5 == 5 → true"]
  H["Operation: 5 === '5'"] --> I["Step 1: Strict Check"]
  I --> J["Types differ → false"]

Best Practices:

  • Use strict equality (===) to avoid coercion.
  • Use typeof to check types explicitly:
    typeof 42;      // "number"
    typeof "hello"; // "string"
    typeof null;    // "object" (historical bug!)
    

Worked Example: Phone Number Validation

function validatePhone(phone) {
  // Check if input is a string and matches 10-digit pattern
  return typeof phone === "string" &&
         /^\d{10}$/.test(phone);
}
validatePhone("9800123456"); // true
validatePhone("98001234");   // false

Real-World Use: Ncell’s IVR system uses regex to validate phone inputs before processing calls.


5. Common Pitfalls and Debugging

  1. Hoisting:

    console.log(age); // undefined (var is hoisted)
    var age = 25;
    

    Fix: Always declare variables at the top of their scope or use let/const.

  2. == vs. ===:

    0 == false;   // true (coercion)
    0 === false;  // false (strict)
    
  3. Mutable Objects:

    let obj = { a: 1 };
    function modify(o) { o.a = 2; }
    modify(obj);
    console.log(obj.a); // 2 (objects are passed by reference)
    
  4. Debugging with Chrome DevTools:

    • Console: Log variables (console.log(varName)).
    • Sources Panel: Step through code line-by-line.
    • Call Stack: See nested function calls (e.g., in Daraz’s checkout flow).

Caption: Tracing a function call in a WhatsApp Web message-sending script.


In the Real World

JavaScript’s data types and functions power the logic behind apps Nepal’s students use daily:

  1. eSewa’s Payment Validation

    • Idea Used: Type checking + regex for phone/email validation.
    • How: Before processing a payment, eSewa checks:
      if (typeof phone === "string" && /^\d{10}$/.test(phone)) {
        proceedToPayment();
      }
      
    • Why: Prevents fraud by ensuring inputs match expected formats.
  2. Khalti’s Transaction Logging

    • Idea Used: Objects and arrays to store transaction data.
    • How: Each transaction is an object in an array:
      const transactions = [
        { id: "TXN001", amount: 500, status: "completed" },
        { id: "TXN002", amount: 2000, status: "pending" }
      ];
      
    • Why: Enables filtering (e.g., transactions.filter(t => t.status === "completed")).
  3. Pathao’s Order Queue

    • Idea Used: Functions and closures to manage rider assignments.
    • How: Pathao uses a function to assign the nearest rider:
      function assignRider(orders) {
        return orders.sort((a, b) => a.distance - b.distance)[0];
      }
      
    • Why: Ensures efficient routing by leveraging array methods and comparisons.
  4. NEPSE Stock Price Updates

    • Idea Used: Asynchronous functions (covered later) to fetch real-time data.
    • How: NEPSE’s website uses fetch() to get stock prices:
      async function getStockPrice(symbol) {
        const response = await fetch(`/api/stock/${symbol}`);
        return response.json();
      }
      
    • Why: Prevents UI freezing while waiting for server responses.
  5. WhatsApp’s Message Encryption

    • Idea Used: Boolean logic for encryption flags.
    • How: Messages are marked as encrypted with:
      const isEncrypted = true;
      if (isEncrypted) {
        applyAES256Cipher(message);
      }
      
    • Why: Ensures end-to-end security using simple but critical type checks.

Worked Example: Daraz Order Processing

Scenario: Daraz needs to validate an order before processing it. The order has:

  • A user ID (must be a number).
  • A phone number (must be a 10-digit string).
  • A password (must be at least 8 characters with a number).

Solution:

function validateOrder(userId, phone, password) {
  // Check userId is a number
  if (typeof userId !== "number" || isNaN(userId)) {
    return "Invalid user ID";
  }
  // Check phone is 10-digit string
  if (typeof phone !== "string" || !/^\d{10}$/.test(phone)) {
    return "Invalid phone number";
  }
  // Check password meets criteria
  if (typeof password !== "string" ||
      password.length < 8 ||
      !/\d/.test(password)) {
    return "Password too weak";
  }
  return "Order valid!";
}

// Test cases
validateOrder(12345, "9800123456", "secure123"); // "Order valid!"
validateOrder("abc", "9800123", "weak");         // "Invalid user ID"

Visualization of Validation Flow:

flowchart TD
  A["Start"] --> B{"User ID Valid?"}
  B -->|"No"| C["Return 'Invalid user ID'"]
  B -->|"Yes"| D{"Phone Valid?"}
  D -->|"No"| E["Return 'Invalid phone'"]
  D -->|"Yes"| F{"Password Valid?"}
  F -->|"No"| G["Return 'Weak password'"]
  F -->|"Yes"| H["Return 'Order valid!'"]

Comparison: JavaScript vs. Other Languages

Feature JavaScript Python Java
Variable Declaration let, const, var var (dynamic typing) final, static
Type Checking Dynamic (coercion) Dynamic Static (compiled)
Function Scope Block/Function Block/Module Block/Method
Hoisting var hoisted No hoisting No hoisting
Default Parameters Supported (ES6) Supported Supported (Java 8+)
Closures First-class First-class Limited (lambdas)

Exam Tip: How to Score Full Marks

  1. Data Types:

    • Must-know: List all 8 primitives + BigInt/Object. Explain mutability and storage differences.
    • Common mistake: Forgetting Symbol or confusing null/undefined.
    • Exam trick: If asked to "discuss," use a comparison table (like above) with 3–4 key columns.
  2. Variables:

    • Focus on scope: Draw a scope diagram (like the stateDiagram-v2 above) for var vs. let/const.
    • Practical tip: Always use const by default unless reassignment is needed.
  3. Functions:

    • Syntax: Know declaration, expression, and arrow functions. Show one example of each.
    • Parameters: Explain rest parameters (...args) and default values.
    • Real-world link: Relate to form validation (e.g., "Write a function to validate an email").
  4. Type Coercion:

    • Key point: == coerces; === does not. Show 3 examples (e.g., 0 == false, "5" + 2).
    • Debugging: Mention typeof and how to avoid coercion bugs.
  5. Worked Examples:

    • Structure: Input → Logic → Output → Edge Cases.
    • Real-world tie-in: Always link to a Nepali app (e.g., "This is how eSewa checks phone numbers").
    • Visual aid: Use flowcharts or tables to organize logic.

Sample Exam Question Breakdown: Question: "Write a JavaScript program to take two integers and find their sum if both are even; otherwise, find their difference." Full-Mark Answer:

function evenOddSumDiff(a, b) {
  // Check if both are even
  if (Number.isInteger(a) && Number.isInteger(b) &&
      a % 2 === 0 && b % 2 === 0) {
    return a + b; // Sum if both even
  } else {
    return Math.abs(a - b); // Difference otherwise
  }
}

// Test cases
console.log(evenOddSumDiff(4, 6));  // 10 (4+6)
console.log(evenOddSumDiff(3, 5));  // 2 (5-3)
console.log(evenOddSumDiff(2, 3));  // 1 (3-2)

Why this scores full marks:

  • Input validation: Checks Number.isInteger.
  • Logic: Clear if-else with comments.
  • Edge cases: Includes odd/even combinations.
  • Output: Uses Math.abs for consistent results.

Final Reminder:

  • Visuals > Text: Always draw diagrams for scope, functions, or validation flows.
  • Real-world links: Exams often ask for applications—be ready to tie concepts to eSewa, Daraz, or Ncell.
  • Debugging: Mention tools like Chrome DevTools to show practical skills.

Based on the TU BITM syllabus for Web Technology I (IT237), unit 5.

Discussion

Loading…