Skip to content
    SeaCode
    Learning tracksCode ArenaWorkshops & EventsInstructors
    Log inSign up
    JSJavaScript

    Getting started

    • What is JavaScript?
    • Variables: let, const and var
    • Data types
    • Type conversion

    Operators and strings

    • Arithmetic and assignment
    • Comparison and logic
    • Strings and template literals
    • String methods
    • Numbers and Math

    Control flow

    • Conditions: if and else
    • switch and the ternary operator
    • Loops: for and while
    • Challenge: FizzBuzz

    Functions

    • Functions
    • Arrow functions
    • Parameters: default, rest and spread
    • Scope and closures
    • Callbacks and higher-order functions

    Arrays

    • Array basics
    • map, filter and find
    • reduce and sorting
    • Destructuring

    Objects

    • Object basics
    • Copies and references
    • Methods and this
    • JSON and optional chaining

    Classes and OOP

    • Classes
    • Inheritance

    JavaScript in the page

    • Controlling the page (DOM)
    • Creating elements
    • Events
    • Forms and validation
    • Saving in the browser (localStorage)

    Errors and async

    • Handling errors: try and catch
    • Timers and the event loop
    • Promises
    • async and await
    • Fetching data from an API

    Practical tools and techniques

    • Searching with regular expressions
    • Cancellation and stale results
    • Testing and debugging JavaScript

    Modern JavaScript and a project

    • Map and Set
    • Dates and localised formatting
    • Modules: import and export
    • Project: a complete to-do app
    JavaScript

    Modern JavaScript and a project · Lesson 45 of 45

    Project: a complete to-do app

    Use everything you learned in a real app that saves its data.

    15 minutes2 games

    This app uses the DOM, events, arrays (map, filter), objects, localStorage, event delegation and the data → render idea. Read it line by line, then try the challenges below.

    HTML
    <style>
      body { font-family: system-ui; max-width: 420px }
      form { display: flex; gap: 6px }
      input { flex: 1; padding: 8px }
      li { display: flex; gap: 8px; align-items: center; padding: 6px 0 }
      li.done span { text-decoration: line-through; color: #999 }
      .filters button.active { font-weight: 700 }
    </style>
    
    <h2>My tasks</h2>
    <form id="form"><input id="text" placeholder="New task" required><button>Add</button></form>
    <p class="filters">
      <button data-filter="all" class="active">All</button>
      <button data-filter="open">Open</button>
      <button data-filter="done">Done</button>
    </p>
    <ul id="list"></ul>
    <p id="count"></p>
    
    <script>
      let tasks = []
      let filter = "all"
      try { tasks = JSON.parse(localStorage.getItem("tasks")) ?? [] } catch {}
    
      const save = () => { try { localStorage.setItem("tasks", JSON.stringify(tasks)) } catch {} }
    
      function render() {
        const visible = tasks.filter((t) => filter === "all" || (filter === "done" ? t.done : !t.done))
        const list = document.querySelector("#list")
        list.replaceChildren(...visible.map((t) => {
          const li = document.createElement("li")
          li.dataset.id = t.id
          li.className = t.done ? "done" : ""
          li.innerHTML = '<input type="checkbox"> <span></span> <button data-action="delete">✕</button>'
          li.querySelector("input").checked = t.done
          li.querySelector("span").textContent = t.text
          return li
        }))
        const open = tasks.filter((t) => !t.done).length
        document.querySelector("#count").textContent = open + " task(s) left"
      }
    
      document.querySelector("#form").addEventListener("submit", (e) => {
        e.preventDefault()
        const input = document.querySelector("#text")
        tasks.push({ id: Date.now(), text: input.value.trim(), done: false })
        input.value = ""
        save(); render()
      })
    
      document.querySelector("#list").addEventListener("click", (e) => {
        const id = Number(e.target.closest("li")?.dataset.id)
        if (e.target.matches('input[type="checkbox"]')) {
          const task = tasks.find((t) => t.id === id)
          task.done = !task.done
        } else if (e.target.dataset.action === "delete") {
          tasks = tasks.filter((t) => t.id !== id)
        } else return
        save(); render()
      })
    
      document.querySelector(".filters").addEventListener("click", (e) => {
        if (!e.target.dataset.filter) return
        filter = e.target.dataset.filter
        document.querySelectorAll(".filters button").forEach((b) => b.classList.toggle("active", b === e.target))
        render()
      })
    
      render()
    </script>

    Add tasks, tick them, filter them and delete them.

    Important

    Notice the user's text goes in with textContent, never into innerHTML, to prevent XSS. innerHTML is used only for the fixed structure we wrote ourselves.

    Interview question

    With 10,000 tasks, what would slow this app down, and how would you improve it?

    Quick question

    Why one listener on #list instead of one per checkbox?

    Exercise

    Logic challenge: write summary(tasks) returning text like 2 done, 1 open.

    Expected output: 2 done, 1 open

    JavaScript
    const tasks = [
      { text: "Read", done: true },
      { text: "Code", done: false },
      { text: "Sleep", done: true },
    ]
    

    Learn more from

    • MDN: Your first website: adding interactivitydeveloper.mozilla.org
    • javascript.info: Event delegationjavascript.info
    • OWASP: Cross Site Scripting (XSS)owasp.org

    Played 0 of 2 games

    Sign in to save your progress and earn XP.

    PreviousModules: import and export🎉 خلّصت JavaScript!
    SeaCode

    Learn to code for real, online or at our branch in front of Cairo University, Giza.

    Learn

    • All courses
    • Interactive tutorials
    • Interview practice problems
    • Mock interview
    • Learning tracks
    • Code Arena
    • Workshops & Events
    • Knowledge library
    • Team projects

    Your account

    • Log in
    • Sign up
    • Learning plan
    • Certificates
    • Site map

    Contact us

    • WhatsApp
    • 010 9094 1104
    • In front of Cairo University, Giza

    © 2026 SeaCode. All rights reserved.