Logo

📘 Learn JavaScript

JavaScript is the programming language of the Web. It powers dynamic behavior on most websites and is essential for modern web development.

What is JavaScript?
JavaScript is a versatile, high-level programming language that runs in web browsers and on servers (Node.js). It was created in 1995 and has become the backbone of interactive web experiences, powering everything from simple animations to complex web applications.

  • Client-Side: JavaScript runs in your browser, allowing you to interact with web pages, validate forms, and create dynamic content.
  • Server-Side: With Node.js, JavaScript can build scalable backend services and APIs.
  • Universal: JavaScript is used for mobile apps, desktop apps, IoT devices, and more.

Why Learn JavaScript?

  • It’s the most popular language for web development.
  • All major browsers support JavaScript natively.
  • It’s beginner-friendly and has a huge community.
  • Learning JavaScript opens doors to frameworks like React, Vue, Angular, and backend development with Node.js.

Quick Facts

  • JavaScript is not Java! They are different languages.
  • JavaScript is dynamically typed and interpreted.
  • It supports object-oriented, functional, and event-driven programming styles.

Tip for Beginners: Start by experimenting with small code snippets. Use browser developer tools (F12) to write and test JavaScript live!

How JavaScript Works

  • JavaScript code is executed line-by-line by the browser’s JavaScript engine.
  • It can manipulate HTML and CSS to create interactive pages.
  • Modern JavaScript supports modules, async programming, and advanced features.

Variables & Data Types

Variables are containers for storing data values. In JavaScript, you can declare variables using var, let, or const:

  • var: Function-scoped, can be redeclared and updated. (Avoid in modern code)
  • let: Block-scoped, can be updated but not redeclared in the same scope.
  • const: Block-scoped, cannot be updated or redeclared. Use for values that should not change.
// Variable declarations
var x = 10; // function-scoped
let y = 20; // block-scoped
const z = 30; // block-scoped, cannot be reassigned

// Scope example
if (true) {
  var a = 1;
  let b = 2;
  const c = 3;
}
console.log(a); // 1 (var is accessible)
// console.log(b); // Error (let is block-scoped)
// console.log(c); // Error (const is block-scoped)

// Data types
let score = 99.5; // Number
let message = "Hello!"; // String
let isActive = false; // Boolean
let nothing = null; // Null
let notDefined; // Undefined
let person = { name: "Bob", age: 25 }; // Object
let fruits = ["Apple", "Banana"]; // Array (object)
let sym = Symbol("id"); // Symbol

console.log(typeof score);      // number
console.log(typeof message);    // string
console.log(typeof isActive);   // boolean
console.log(typeof nothing);    // object (null is a special case)
console.log(typeof notDefined); // undefined
console.log(typeof person);     // object
console.log(typeof fruits);     // object
console.log(typeof sym);        // symbol

JavaScript Data Types:

  • Number: 42, 3.14
  • String: "Hello", 'World'
  • Boolean: true, false
  • Null: null (intentional absence of value)
  • Undefined: undefined (variable declared but not assigned)
  • Object: { name: "Alice" }
  • Array: [1, 2, 3] (a type of object)
  • Symbol: Symbol("desc") (unique, immutable value)

Type Conversion: JavaScript automatically converts types when needed (type coercion). Use parseInt(), parseFloat(), String(), Boolean() for explicit conversion.

let num = "42";
console.log(typeof num); // string
let converted = Number(num);
console.log(typeof converted); // number

Advanced Notes

  • Hoisting: var declarations are hoisted to the top of their scope. let and const are not initialized until their definition is evaluated.
  • Mutability: const objects and arrays can have their contents changed, but the variable cannot be reassigned.
  • Dynamic Typing: Variables can change type at runtime.
  • Best Practice: Prefer let and const for modern JavaScript. Use const by default unless you need to reassign.

Functions

Functions are reusable blocks of code that help organize logic, avoid repetition, and make your code modular. You can define functions using the function keyword, as function expressions, or as arrow functions.

  • Declaration: function myFunc() { ... }
  • Parameters: Functions can accept zero or more parameters.
  • Return Values: Use return to send a value back to the caller.
  • Scope: Variables declared inside a function are local to that function.
// Function declaration
function greet(name) {
  return "Hello, " + name;
}
console.log(greet("Bob")); // Output: Hello, Bob

// Function expression
const square = function(x) {
  return x * x;
};
console.log(square(5)); // Output: 25

// Arrow function
const add = (a, b) => a + b;
console.log(add(2, 3)); // Output: 5

// Default parameters
function welcome(name = "Guest") {
  return `Welcome, ${name}!`;
}
console.log(welcome()); // Output: Welcome, Guest!

// Rest parameters
function sum(...nums) {
  return nums.reduce((acc, n) => acc + n, 0);
}
console.log(sum(1, 2, 3, 4)); // Output: 10

// Recursion
function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}
console.log(factorial(5)); // Output: 120

Tips:

  • Functions can be nested and returned from other functions (higher-order functions).
  • Arrow functions do not have their own this or arguments object.
  • Use default parameters to make your functions more flexible.
  • Use recursion for problems that can be broken down into smaller subproblems.

Advanced Notes

  • Function Expression vs Declaration: Declarations are hoisted, expressions are not.
  • Arrow Functions: Great for short callbacks, but avoid for object methods or constructors.
  • Closures: Functions can "remember" variables from their outer scope.
  • Best Practice: Name your functions clearly and keep them focused on a single task.

Arrays and Objects

Arrays and objects are the main ways to store and organize data in JavaScript. Arrays hold ordered lists, while objects store key-value pairs.

Arrays

  • Create with []: let arr = [1, 2, 3]
  • Access by index: arr[0] is the first element.
  • Common methods: push, pop, shift, unshift, slice, splice, forEach, map, filter, reduce
  • Arrays can hold any type, including other arrays (multidimensional).
let fruits = ["Apple", "Banana", "Cherry"];
console.log(fruits[1]); // Output: Banana
fruits.push("Orange"); // Add to end
console.log(fruits); // ["Apple", "Banana", "Cherry", "Orange"]
fruits.pop(); // Remove last
console.log(fruits); // ["Apple", "Banana", "Cherry"]
fruits.forEach(fruit => console.log(fruit)); // Iterate

// Multidimensional array
let matrix = [[1,2],[3,4]];
console.log(matrix[1][0]); // Output: 3

Objects

  • Create with {}: let person = { name: "John", age: 30 }
  • Access properties: person.name or person["age"]
  • Add/update: person.city = "Delhi"
  • Delete: delete person.age
  • Objects can have methods (functions as properties).
let person = {
  name: "John",
  age: 30,
  greet: function() {
    return `Hi, I'm ${this.name}`;
  }
};
console.log(person.greet()); // Output: Hi, I'm John

// Destructuring
let { name, age } = person;
console.log(name, age); // John 30

// Spread operator
let clone = { ...person, city: "Delhi" };
console.log(clone);

Tips:

  • Use Object.keys(), Object.values(), Object.entries() to work with object properties.
  • Arrays are zero-indexed. Objects are unordered collections.
  • Use destructuring and spread for cleaner code.

Advanced Notes

  • Arrays: Can be sparse (missing indices), and are objects under the hood.
  • Objects: Property names can be strings or symbols. Use computed properties: { [key]: value }
  • Best Practice: Use const for arrays/objects unless you need to reassign.

Conditionals and Loops

Conditionals let you run code based on conditions. Loops let you repeat code. These are essential for controlling program flow.

Conditionals

  • if/else: Run code if a condition is true, otherwise run alternative code.
  • else if: Check multiple conditions.
  • switch: Handle multiple possible values for a variable.
let age = 20;
if (age > 18) {
  console.log("Adult");
} else if (age > 12) {
  console.log("Teenager");
} else {
  console.log("Child");
}

let fruit = "Banana";
switch (fruit) {
  case "Apple":
    console.log("Apple selected");
    break;
  case "Banana":
    console.log("Banana selected");
    break;
  default:
    console.log("Other fruit");
}

Loops

  • for: Repeat code a set number of times.
  • while: Repeat code while a condition is true.
  • do...while: Like while, but runs at least once.
  • for...of: Loop over iterable objects (arrays, strings).
  • for...in: Loop over object properties.
// for loop
for (let i = 0; i < 3; i++) {
  console.log(i);
}

// while loop
let j = 0;
while (j < 3) {
  console.log(j);
  j++;
}

// do...while loop
let k = 0;
do {
  console.log(k);
  k++;
} while (k < 3);

// for...of loop
let arr = ["a", "b", "c"];
for (let item of arr) {
  console.log(item);
}

// for...in loop
let obj = { x: 1, y: 2 };
for (let key in obj) {
  console.log(key, obj[key]);
}

// Nested loops
for (let x = 1; x <= 2; x++) {
  for (let y = 1; y <= 2; y++) {
    console.log(`x=${x}, y=${y}`);
  }
}

Tips:

  • Use break to exit a loop early, continue to skip to the next iteration.
  • Loops can be nested for complex logic.
  • Use for...of for arrays, for...in for objects.
  • Be careful with infinite loops (condition never becomes false).

Advanced Notes

  • Performance: Prefer for or forEach for large arrays.
  • Best Practice: Keep loop logic simple and avoid deeply nested loops when possible.
  • Switch: Use switch for multiple discrete values, but avoid fall-through unless needed.

Arrow Functions

Arrow functions (=>) are a modern, concise way to write functions in JavaScript. They are especially useful for short callbacks and functional programming. Arrow functions do not have their own this, arguments, super, or new.target bindings.

  • Syntax: (param1, param2) => expression
  • Implicit Return: If the body is a single expression, the value is returned automatically.
  • Single Parameter: Parentheses can be omitted: x => x * 2
  • No this binding: Useful for callbacks, but not for object methods or constructors.
// Basic arrow function
const add = (a, b) => a + b;
console.log(add(2, 3)); // Output: 5

// Single parameter, implicit return
const greet = name => `Hi, ${name}`;
console.log(greet("Sam")); // Output: Hi, Sam

// No parameters
const getTime = () => new Date().toLocaleTimeString();
console.log(getTime());

// Multiline body (use curly braces)
const multiply = (a, b) => {
  const result = a * b;
  return result;
};
console.log(multiply(4, 5)); // Output: 20

// Arrow function in array methods
let nums = [1, 2, 3];
let squares = nums.map(n => n * n);
console.log(squares); // [1, 4, 9]

// Arrow functions and 'this'
const person = {
  name: "Alex",
  sayHi: function() {
    setTimeout(() => {
      console.log(`Hi, I'm ${this.name}`); // 'this' refers to person
    }, 500);
  }
};
person.sayHi();

Tips:

  • Use arrow functions for short callbacks (e.g., map, filter, forEach).
  • Do not use arrow functions for object methods or constructors.
  • Arrow functions cannot use arguments object. Use rest parameters (...args) instead.
  • Parentheses are required for zero or multiple parameters.

Advanced Notes

  • Lexical this: Arrow functions capture the this value of their enclosing scope.
  • No prototype: Arrow functions do not have a prototype property.
  • Cannot be used as constructors: You cannot use new with arrow functions.
  • Best Practice: Use arrow functions for callbacks and functional code, but use regular functions for object methods and constructors.

Closures

A closure is a feature in JavaScript where an inner function has access to the outer (enclosing) function’s variables—even after the outer function has finished executing. Closures are fundamental for data privacy, factory functions, and advanced patterns like currying and memoization.

  • Scope Chain: Inner functions remember variables from their parent scope.
  • Data Privacy: Closures allow you to create private variables and methods.
  • Practical Uses: Event handlers, callbacks, module patterns, and more.
// Basic closure example
function outer() {
  let counter = 0;
  return function inner() {
    counter++;
    console.log(counter);
  };
}
const count = outer();
count(); // 1
count(); // 2

// Data privacy with closures
function makeSecret(secret) {
  return function reveal() {
    return secret;
  };
}
const getSecret = makeSecret("hidden value");
console.log(getSecret()); // "hidden value"

// Factory function using closure
function multiplier(factor) {
  return function(x) {
    return x * factor;
  };
}
const double = multiplier(2);
console.log(double(5)); // 10

// Closure in event handler
function setupButton() {
  let clicks = 0;
  document.getElementById("myBtn").onclick = function() {
    clicks++;
    console.log("Clicked", clicks, "times");
  };
}
// Call setupButton() after page loads and click #myBtn

Tips:

  • Closures are used in callbacks, event handlers, and module patterns.
  • Use closures to create private state in functions and objects.
  • Closures are the basis for currying, partial application, and memoization.

Advanced Notes

  • Garbage Collection: Variables in closures are not garbage collected until all references are gone.
  • Memory Usage: Be mindful of memory leaks with closures in long-lived objects (e.g., event listeners).
  • Best Practice: Use closures for encapsulation and modular code, but avoid excessive nesting for readability.
  • Debugging: Use browser dev tools to inspect closure scopes.

Callbacks, Promises & Async/Await

JavaScript is single-threaded but can handle asynchronous operations using callbacks, promises, and async/await. Asynchronous code is essential for tasks like API calls, timers, file operations, and user interactions. Understanding async patterns helps you write non-blocking, responsive applications.

  • Callback: A function passed as an argument to be executed later (e.g., after a timer or event).
  • Promise: An object representing the eventual completion (or failure) of an async operation.
  • Async/Await: Syntactic sugar for working with promises, making async code look synchronous.
// Callback example
setTimeout(() => console.log("Hello after 1 sec"), 1000);

// Callback hell (nesting)
setTimeout(() => {
  console.log("Step 1");
  setTimeout(() => {
    console.log("Step 2");
    setTimeout(() => {
      console.log("Step 3");
    }, 1000);
  }, 1000);
}, 1000);

// Promise example
const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Done!"), 1000);
});
promise.then(res => console.log(res));

// Chaining promises
function asyncAdd(a, b) {
  return new Promise(resolve => {
    setTimeout(() => resolve(a + b), 500);
  });
}
asyncAdd(2, 3)
  .then(sum => {
    console.log("Sum:", sum);
    return asyncAdd(sum, 4);
  })
  .then(result => console.log("Result:", result));

// Error handling with promises
const failPromise = new Promise((_, reject) => {
  setTimeout(() => reject("Something went wrong!"), 700);
});
failPromise.catch(err => console.error("Error:", err));

// Async/Await example
async function fetchData() {
  try {
    let result = await promise;
    console.log(result);
    let sum = await asyncAdd(5, 7);
    console.log("Async sum:", sum);
  } catch (e) {
    console.error("Async error:", e);
  }
}
fetchData();

// Parallel async with Promise.all
async function parallelTasks() {
  let results = await Promise.all([
    asyncAdd(1, 2),
    asyncAdd(3, 4),
    asyncAdd(5, 6)
  ]);
  console.log("Parallel results:", results);
}
parallelTasks();

Tips:

  • Use try/catch with async/await for error handling.
  • Chain promises for sequential async operations.
  • Use Promise.all for running async tasks in parallel.
  • Callbacks can lead to deeply nested code (callback hell); prefer promises or async/await for complex flows.

Advanced Notes

  • Promise States: pending, fulfilled, rejected.
  • Async/Await: Works only inside async functions.
  • Best Practice: Always handle errors in async code to avoid silent failures.
  • Race Conditions: Use Promise.race to get the result of the fastest promise.
  • Microtasks: Promises are scheduled as microtasks, which run after the current script but before rendering.

Error Handling

Error handling in JavaScript is crucial for building robust applications. Use try, catch, and finally to gracefully handle errors, prevent crashes, and debug issues. You can throw custom errors, catch exceptions, and ensure cleanup code runs regardless of success or failure.

  • try/catch: Wrap risky code to catch exceptions and handle them.
  • finally: Runs after try and catch, useful for cleanup.
  • throw: Create and throw custom errors.
  • Custom Error Classes: Extend Error for better error management.
  • Async Errors: Handle errors in promises and async/await using .catch() or try/catch.
// Basic try/catch/finally
try {
  throw new Error("Something went wrong");
} catch (err) {
  console.error("Caught error:", err.message);
} finally {
  console.log("Cleanup code runs here.");
}

// Throwing custom errors
function divide(a, b) {
  if (b === 0) {
    throw new Error("Division by zero!");
  }
  return a / b;
}
try {
  console.log(divide(10, 0));
} catch (e) {
  console.error("Custom error:", e.message);
}

// Custom error class
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}
function validateAge(age) {
  if (age < 0) throw new ValidationError("Age cannot be negative");
  return age;
}
try {
  validateAge(-5);
} catch (e) {
  if (e instanceof ValidationError) {
    console.error("Validation error:", e.message);
  } else {
    console.error("Other error:", e);
  }
}

// Error handling in async code
async function fetchData() {
  try {
    await Promise.reject("Async error!");
  } catch (e) {
    console.error("Caught async error:", e);
  }
}
fetchData();

// Using .catch() with promises
Promise.reject("Promise failed!")
  .catch(err => console.error("Promise error:", err));
fetchData(); // Using .catch() with promises Promise.reject("Promise failed!") .catch(err => console.error("Promise error:", err));

Tips:

  • Always handle errors in asynchronous code using .catch() or try/catch.
  • Use custom error classes for better error categorization.
  • Use finally for cleanup tasks (closing files, releasing resources).
  • Log errors for debugging and user feedback.

Advanced Notes

  • Error Propagation: Errors bubble up the call stack until caught.
  • Global Error Handling: Use window.onerror or process.on('uncaughtException') for global error capture.
  • Best Practice: Never silently ignore errors; always log or handle them.
  • Async/Await: Use try/catch inside async functions for proper error handling.
  • Validation: Validate user input and throw errors for invalid data.

DOM Manipulation

The Document Object Model (DOM) lets you interact with HTML elements using JavaScript. You can change content, styles, structure, and respond to user actions. DOM manipulation is essential for building interactive web applications, handling events, and updating the UI dynamically.

  • Select Elements: getElementById, getElementsByClassName, querySelector, querySelectorAll
  • Change Content: innerText, innerHTML, textContent
  • Change Styles: element.style, classList
  • Events: addEventListener for clicks, input, mouse, keyboard, etc.
  • Create/Remove Elements: createElement, appendChild, removeChild
// Select and change content
document.getElementById("demo").innerText = "Changed by JavaScript!";

// Change styles
document.getElementById("demo").style.color = "#00FFDD";
document.getElementById("demo").classList.add("highlight");

// Add event listener
const btn = document.getElementById("myBtn");
btn.addEventListener("click", function() {
  alert("Button clicked!");
});

// Create and add new element
const newDiv = document.createElement("div");
newDiv.innerText = "I am new!";
document.body.appendChild(newDiv);

// Remove element
setTimeout(() => {
  document.body.removeChild(newDiv);
}, 2000);

// Query selector for advanced selection
let firstItem = document.querySelector(".item");
if (firstItem) firstItem.style.background = "#FFC107";

// Event delegation example
document.getElementById("list").addEventListener("click", function(e) {
  if (e.target.tagName === "LI") {
    alert("List item clicked: " + e.target.innerText);
  }
});
  • Use querySelector and classList for advanced DOM operations.
  • Use event delegation for efficient event handling on lists and dynamic elements.
  • Always check if an element exists before manipulating it.
  • Use innerHTML with caution to avoid XSS vulnerabilities.

Advanced Notes

  • Performance: Minimize DOM updates for better performance.
  • Fragment: Use DocumentFragment for batch DOM changes.
  • MutationObserver: Observe DOM changes for advanced use cases.
  • Accessibility: Update ARIA attributes for accessible web apps.
  • Best Practice: Separate logic and presentation; avoid inline event handlers.

Classes and OOP

JavaScript supports object-oriented programming (OOP) using classes. Classes are blueprints for creating objects with properties and methods. OOP helps organize code, promote reuse, and model real-world entities. Modern JavaScript classes support inheritance, encapsulation, static methods, private fields, and more.

  • Class Declaration: class MyClass { ... }
  • Constructor: constructor() method for initializing properties.
  • Methods: Functions defined inside the class.
  • Inheritance: extends keyword to create subclasses.
  • Static Methods: static keyword for class-level methods.
  • Private Fields: #field syntax for encapsulation.
// Basic class
class Person {
  constructor(name) {
    this.name = name;
  }
  greet() {
    console.log("Hi, I'm " + this.name);
  }
}
const p = new Person("Alice");
p.greet();

// Inheritance
class Student extends Person {
  constructor(name, grade) {
    super(name);
    this.grade = grade;
  }
  showGrade() {
    console.log(`${this.name}'s grade: ${this.grade}`);
  }
}
const s = new Student("Bob", "A");
s.greet();
s.showGrade();

// Static method
class MathUtil {
  static add(a, b) {
    return a + b;
  }
}
console.log(MathUtil.add(2, 3)); // 5

// Private fields and methods
class Counter {
  #count = 0;
  increment() {
    this.#count++;
    return this.#count;
  }
  getCount() {
    return this.#count;
  }
}
const counter = new Counter();
console.log(counter.increment()); // 1
console.log(counter.getCount()); // 1

// Class expression
const Animal = class {
  speak() {
    console.log("Animal speaks");
  }
};
const a = new Animal();
a.speak();

Tips:

  • Use inheritance to create subclasses and extend functionality.
  • Use super() to call parent class methods.
  • Use private fields (#field) for encapsulation.
  • Use static methods for utility functions that don't depend on instance data.
  • Class expressions allow you to define classes anonymously.

Advanced Notes

  • Polymorphism: Subclasses can override parent methods.
  • Instance vs Static: Instance methods operate on object data; static methods on class data.
  • Private Methods: Use #method() for private logic.
  • Best Practice: Keep classes focused, use composition for complex logic.
  • Mixins: Use mixins to add reusable functionality to classes.

LocalStorage

LocalStorage allows you to store key-value data in the browser that persists across sessions and page reloads. It's useful for saving user preferences, app state, and small datasets. Data is stored as strings and is accessible via JavaScript.

  • Set Item: localStorage.setItem(key, value)
  • Get Item: localStorage.getItem(key)
  • Remove Item: localStorage.removeItem(key)
  • Clear All: localStorage.clear()
  • Storage Event: Listen for changes with window.addEventListener('storage', ...)
// Store a string
localStorage.setItem("username", "Alice");
let user = localStorage.getItem("username");
console.log(user); // Output: Alice

// Store an object
const settings = { theme: "dark", fontSize: 18 };
localStorage.setItem("settings", JSON.stringify(settings));
const loaded = JSON.parse(localStorage.getItem("settings"));
console.log(loaded.theme); // Output: dark

// Remove an item
localStorage.removeItem("username");

// Clear all data
// localStorage.clear();

// Listen for changes (in other tabs/windows)
window.addEventListener('storage', function(e) {
  console.log('Storage changed:', e.key, e.newValue);
});

Tips:

  • Data in localStorage is always stored as strings. Use JSON.stringify and JSON.parse for objects and arrays.
  • localStorage is synchronous; avoid storing large data to prevent UI blocking.
  • Use sessionStorage for data that should only persist for a single tab/session.
  • Check for storage quota limits (usually 5-10MB per origin).
  • Use try/catch for robust error handling when reading/writing storage.

Advanced Notes

  • Security: Data is accessible to any script on the page; do not store sensitive information.

Fetch API (AJAX)

The Fetch API lets you make HTTP requests to servers and APIs. It's promise-based and replaces older AJAX methods.

fetch("https://jsonplaceholder.typicode.com/posts")
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

Tip: Always handle errors with .catch() when using fetch.

Advanced Note

  • Use async/await for cleaner fetch code.
  • Handle network errors and invalid responses.

Regular Expressions

Regular expressions (regex) are patterns used to match, search, and manipulate strings. They are powerful tools for validation, parsing, and text processing in JavaScript. Regex can be used for simple checks or complex pattern matching.

  • Creation: /pattern/flags or new RegExp("pattern", "flags")
  • Common Flags: i (ignore case), g (global), m (multiline)
  • Methods: .test(), .exec(), .match(), .replace(), .split()
  • Character Classes: \d (digit), \w (word), \s (whitespace)
  • Anchors: ^ (start), $ (end)
  • Quantifiers: *, +, ?, {n,m}
// Basic usage
let pattern = /hello/i;
console.log(pattern.test("Hello World")); // true

// Match email
let email = "test@example.com";
let emailPattern = /^[^@]+@[^@]+\.[^@]+$/;
console.log(emailPattern.test(email)); // true

// Extract numbers from string
let str = "Order #1234, total $56.78";
let nums = str.match(/\d+/g);
console.log(nums); // ["1234", "56", "78"]

// Replace all spaces with dashes
let text = "JavaScript regex is cool!";
let dashed = text.replace(/\s+/g, "-");
console.log(dashed); // JavaScript-regex-is-cool!

// Validate phone number (simple)
let phone = "987-654-3210";
let phonePattern = /^\d{3}-\d{3}-\d{4}$/;
console.log(phonePattern.test(phone)); // true

// Split string by commas or spaces
let data = "apple, banana orange";
let items = data.split(/[ ,]+/);
console.log(items); // ["apple", "banana", "orange"]

// Advanced: Named capture groups (ES2018+)
let date = "2025-07-11";
let datePattern = /(?\d{4})-(?\d{2})-(?\d{2})/;
let match = date.match(datePattern);
console.log(match.groups); // { year: "2025", month: "07", day: "11" }

Tips:

  • Use .test() for boolean checks, .match() for extracting matches.
  • Use online regex testers to build and debug patterns.
  • Escape special characters (e.g., \., \*, \?) in patterns.
  • Use named capture groups for readable extraction (ES2018+).
  • Regex can be hard to read—add comments or break into steps for complex patterns.

Advanced Notes

  • Performance: Complex regex can be slow on large texts; optimize patterns.
  • Unicode: Use u flag for Unicode support.
  • Lookahead/Lookbehind: Use (?=...) and (?<=...) for advanced matching.
  • Best Practice: Validate user input with regex, but also sanitize and check edge cases.
  • Debugging: Use RegExp.prototype.source to inspect pattern source.

Mini Projects

1. Click Counter

<button onclick="increase()">Click Me</button>
<p id="count">0</p>
<script>
let count = 0;
function increase() {
  count++;
  document.getElementById("count").innerText = count;
}
</script>

2. To-Do List

<input id="taskInput"><button onclick="addTask()">Add</button>
<ul id="taskList"></ul>
<script>
function addTask() {
  const input = document.getElementById("taskInput");
  const li = document.createElement("li");
  li.innerText = input.value;
  document.getElementById("taskList").appendChild(li);
  input.value = "";
}
</script>

3. Light On/Off

<button onclick="toggle()">Toggle Light</button>
<div id="bulb" style="width:100px;height:100px;background:gray;"></div>
<script>
let isOn = false;
function toggle() {
  isOn = !isOn;
  document.getElementById("bulb").style.background = isOn ? "yellow" : "gray";
}
</script>

Tip: Try building your own projects by combining these concepts!