Skip to content

JavaScript Essentials

The language of the browser — and the only way to make your HTML respond to clicks, fetch your model API, and update results without reloading. The basics below cover what AI demos actually need.

Table of Contents

Installation / Setup

<!-- at the end of <body>: -->
<script src="app.js"></script>
<!-- or run directly in the DevTools console (F12) -->

Modern JS also runs on servers (Node.js) — useful for quick API testing. No install needed to follow this sheet; open DevTools console and type along.

Core Syntax

Variables & types

let count = 0;              // mutable
const name = "Ada";         // constant reference (prefer const)
var old = 1;                // legacy — avoid

// Types
typeof 42;                  // "number"
typeof "hi";                // "string"
typeof true;                // "boolean"
typeof null;                // "object" (historical quirk!)
typeof [1, 2];              // "object"
typeof { a: 1 };            // "object"

Functions

function add(a, b) { return a + b; }
const add = (a, b) => a + b;          // arrow function (prefer)
const square = x => x * x;            // one param: no parens
add(1, 2);                            // 3

Arrays

const nums = [1, 2, 3];
nums.push(4);                // [1,2,3,4]
nums.map(x => x * 2);        // [2,4,6,8]  — transform
nums.filter(x => x > 1);     // [2,3,4]    — select
nums.reduce((a, b) => a + b, 0);   // 10 — fold
nums.find(x => x === 3);     // 3 — first match
nums.includes(2);            // true
nums.slice(1, 3);            // [2,3]

Objects

const pred = { label: "positive", score: 0.93 };
pred.label;                  // "positive"
pred["score"];               // 0.93
const { label, score } = pred;      // destructuring
const withMore = { ...pred, source: "model-v2" };   // spread copy

Template strings

const model = "xgboost";
console.log(`Running ${model}, score=${pred.score.toFixed(2)}`);

Common Operations

DOM selection & manipulation

document.querySelector(".card");          // first match
document.querySelectorAll("tr");         // NodeList (array-like)
document.getElementById("results");
document.createElement("div");

el.textContent = "hello";                 // safe text (escape for free)
el.innerHTML = "<b>hi</b>";               // HTML (XSS risk with user data!)
el.style.display = "none";                // hide
el.classList.add("error");                // classes
el.hidden = true;

Events

const btn = document.getElementById("run");
btn.addEventListener("click", () => {
  console.log("clicked");
});

document.querySelector("form").addEventListener("submit", (e) => {
  e.preventDefault();            // stop page reload!
  handleForm();
});

// event delegation: one listener for many rows
document.querySelector("table").addEventListener("click", (e) => {
  if (e.target.matches("button.delete")) { ... }
});

Async & fetch (the API call)

async function predict(text) {
  const res = await fetch("/predict", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ text }),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return await res.json();          // parsed JSON -> JS object
}

// usage with error handling
try {
  const data = await predict("Great product!");
  console.log(data.label, data.score);
} catch (err) {
  console.error("prediction failed:", err);
}
Promise helper Use
fetch(url, options) HTTP request
res.ok, res.status, res.statusText response status
res.json(), res.text(), res.blob() parse body
await / async readable async
Promise.all([...]) run requests in parallel
setTimeout(fn, ms) delay

Practical Examples

1. Prediction form wired end-to-end (see html.md for the form)

document.getElementById("sentiment-form")
  .addEventListener("submit", async (e) => {
    e.preventDefault();
    const text = document.getElementById("review").value;
    const out = document.getElementById("result");
    out.textContent = "Analyzing…";
    try {
      const res = await fetch("/predict", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ text }),
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const data = await res.json();
      out.textContent = `Sentiment: ${data.label} (${(data.score * 100).toFixed(1)}%)`;
      out.className = data.label === "positive" ? "badge ok" : "badge error";
    } catch (err) {
      out.textContent = `Error: ${err.message}`;
      out.className = "badge error";
    }
  });

2. Parallel model calls (compare two models)

const [r1, r2] = await Promise.all([
  fetch("/predict", { method: "POST", headers: {"Content-Type": "application/json"},
                      body: JSON.stringify({ text, model: "v1" }) }).then(r => r.json()),
  fetch("/predict", { method: "POST", headers: {"Content-Type": "application/json"},
                      body: JSON.stringify({ text, model: "v2" }) }).then(r => r.json()),
]);
console.log("v1:", r1.score, "v2:", r2.score);

3. Render predictions into a table

function renderTable(rows) {
  const tbody = document.querySelector("#scores tbody");
  tbody.replaceChildren();                       // clear
  for (const r of rows) {
    const tr = document.createElement("tr");
    const tdLabel = document.createElement("td");
    tdLabel.textContent = r.label;
    const tdScore = document.createElement("td");
    tdScore.textContent = (r.value * 100).toFixed(2) + "%";
    tr.append(tdLabel, tdScore);
    tbody.append(tr);
  }
}

Common Patterns

// Debounce: wait for the user to stop typing before calling an API
function debounce(fn, ms = 300) {
  let t;
  return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); };
}
input.addEventListener("input", debounce(async () => {
  const results = await search(input.value);   // autocomplete
}));

// Guard against out-of-order responses (stale results)
let requestId = 0;
input.addEventListener("input", async () => {
  const id = ++requestId;
  const data = await fetchResults(input.value);
  if (id === requestId) render(data);   // drop stale replies
});

Best Practices

  • Prefer const, then let — never var in new code.
  • Use textContent for user data, innerHTML only for trusted markup — XSS is the top web vulnerability (see Cybersecurity).
  • Always check res.ok and wrap fetches in try/catch.
  • Use arrow functions and array methods (map/filter) over manual loops.
  • Keep the DOM in sync in one place — render functions beat scattered updates.
  • Debounce input-driven API calls; cancel/ignore stale async results.
  • Handle loading & error states in the UI, not just the happy path.
  • Learn to debug with console.log, breakpoints, and the Network tab.

Common Mistakes

Mistake Consequence Fix
Forgetting await Promise {<pending>} / undefined data await fetch(...)
Not calling e.preventDefault() Page reloads, state lost Call it first in submit handlers
== loose equality Surprising coercion ("1" == 1) Use ===
Blocking the main thread with a big loop Frozen page Chunk work or move to Web Worker
innerHTML with user input XSS textContent or escape
Attaching listeners before DOM exists "Cannot read properties of null" Script at end of body or DOMContentLoaded
Mixing sync/async error handling Unhandled rejections try/catch around awaits
Mutating props/state ad hoc Hard-to-trace bugs Immutable updates (spread)

Troubleshooting

Symptom Cause Fix
undefined is not a function Typo/import missing Console shows the call site
Cannot read properties of null Element not found/loaded yet Check id; defer script
CORS error on fetch Server lacks header Backend must allow origin (see http.md)
res.json() fails Response isn't JSON (HTML error page) res.text() first; check Network tab
Value is [object Promise] Missing await Add await
Works in console, not on load Timing Wrap in DOMContentLoaded
NaN in math String operands Number(x) / +x coercion deliberately

Official Documentation

Last Updated

2026-09-06 — Initial version.