Step 72. JavaScript Basics — The Language That Brings Web Pages to Life

Step 72. JavaScript Basics — The Language That Brings Web Pages to Life

Level 1 — Programming and the Computer’s Interior | Difficulty ★★★☆☆ | Estimated time: 3 hours

Prerequisites: Step 71 complete; you can build a page with HTML tags and open the developer tools’ (F12) Elements tab. You’ve handled variables and functions in Python.

  • What you need: the page.html from Step 71, a browser, and today’s workbench Node.js (a tool that runs JS outside the browser) — type node --version and if a version appears, you’re set (this book’s verification was done on v24). Without it, you can run the same experiments in the browser’s Console tab.
  • Caution: today’s practice is 100% safe. Every script runs only in files you made and in your terminal.

The page we made last time is pretty but quiet. Press a button, type some text — no response. With HTML and CSS alone, a "static document" is the limit. What breathes life into it is JavaScript (JS). Let me say in advance why JS is essential for a security learner — half of web hacking is "the technique of running JS I wrote in the victim’s browser." That technique’s name is XSS.


1. Learning Objectives

By the end of this chapter, you will be able to:

  • Write basic JS syntax compared with Python (let/const, function, console.log)
  • Embed <script> in an HTML document to make a page "alive"
  • Manipulate the DOM by finding, reading, and changing on-screen elements with document.getElementById
  • Register code that responds to events like clicks with addEventListener
  • Explain why one line of alert("hi") is the starting point of XSS verification

2. Background Knowledge — Today’s Tools and Concepts

Today’s Tools at a Glance

Category Details
Language/environment JavaScript — runs in two places: the browser (Console tab) and Node.js
Today’s tools The browser developer tools’ Console tab (an interactive JS window), node filename.js (terminal execution)
Today’s syntax let/const, function, console.log, backtick strings (`the value is ${x}`), JSON.stringify/parse
Today’s DOM tools document.getElementById, .textContent, .value, addEventListener
Today’s deliverables js_dom.html — a DOM manipulation page, js_event.html — a click counter

2-1. Basic JS Syntax, Compared with Python

A side-by-side comparison for those of you who know Python.

Concept Python JavaScript
Variable x = 5 let x = 5;
Constant (uppercase by convention) const PI = 3.14;
Function def add(a, b): function add(a, b) { return a+b; }
Output print(x) console.log(x);
String interpolation f"the value is {x}" `the value is ${x}`

Three differences: statements end with a semicolon (;), code blocks are wrapped in braces ({ }) instead of indentation, and variables carry let or const in front. let is a changeable variable; const is a constant that can’t be changed once set.

2-2. The script Tag — The Engine Room Inside a Page

JS goes inside a <script> tag. This tag can go anywhere, but in your beginner days, right before </body> is the standard. The reason is execution order. The browser reads the document top to bottom, and if a script runs before its elements, it fails trying to find "elements not yet created." Turning the engine on after the body is fully built — that’s why script goes at the bottom.

2-3. DOM Manipulation and Events

JS’s core actions are two.

  • DOM manipulation: document.getElementById("msg") is the command "bring me the element whose id is msg." Change the found element’s .textContent (its text content), and the screen changes. It’s doing in code what you did by hand in developer tools last time.
  • Events: you register in advance a function to run when an "event" like a click or keypress happens. A reservation saying "when the button is clicked, run this function." Thanks to this, the page responds to the user’s actions.

2-4. JSON — The Common Language of Data

Working with JS, you’ll soon meet a format called JSON (JavaScript Object Notation). It’s a string format for exchanging data, shaped just like a JS object (a bundle of name-tagged values). Most data servers return is in this format, so getting comfortable today pays off immediately when you learn communication.


3. Follow Along

3-1. A Taste of JS with Node — A Workbench Without a Browser

Let’s run JS in the terminal without a browser. Make hello.js.

let x = 5;
function add(a, b) { return a + b; }
console.log(add(x, 10));

let n = 1;
console.log(`clicks: ${n}`);

Input

node hello.js

Output (verified 2026-09-09, Node v24):

15
clicks: 1

How to read it: you made a variable, defined and called a function, and 15 came back; the ${n} inside the backtick string was replaced with 1. Same flow as in Python. console.log corresponds to Python’s print.

Why: for syntax experiments, the terminal is faster than the browser. The reason it works without a browser is that the JS language itself and "the counters the browser provides (document, etc.)" are separate.

Predict: what is console.log("1" + 1)? 2, or 11? (Verified answer: 11 — + between a string and a number is concatenation. Number("1") + 1 is 2. Verified 2026-09-09)

3-2. JSON — Packing and Unpacking

Next, make json_test.js.

let user = { name: "aspiring hacker", level: 1 };
console.log(user.name);

let text = JSON.stringify(user);
console.log(text);

let back = JSON.parse(text);
console.log(back.level);

Output (verified 2026-09-09):

aspiring hacker
{"name":"aspiring hacker","level":1}
1

How to read it: JSON.stringify packs an object into a string, and JSON.parse unpacks a string back into an object. Pack → send → unpack — this is the standard procedure by which data travels on the web.

Why: when a browser and a server talk, data can travel only as "strings." Hence the need for this format that packs structure into a string.

3-3. Where Does document Live? — A Boundary-Checking Experiment

An experiment. Try calling document in Node.

Input

node -e "console.log(document)"

Output (verified 2026-09-09):

ReferenceError: document is not defined

How to read it: a "no such name" error. document is not part of the JS language — it’s a counter the browser provides. So DOM manipulation code works only in the browser (or the browser’s Console tab). Conversely, the syntax experiments so far work anywhere.

Why: knowing the boundary between "the language’s features" and "features the browser lends" is the first step in reading JS errors. When this error appears, interpret it as "tried to use a browser good outside the browser."

3-4. Your First Script — The Power of One Line of alert

Now to the browser. Copy Step 71’s page.html to make js_alert.html, and insert one line right before </body>.

<script>
  alert("hi");
</script>

Input: save → open in the browser.

Screen example: as the page opens, an alert box saying "hi" pops up. You must click OK before you can touch the page.

How to read it: alert is a function that pops an alert box in the browser. A trivial one line, but it’s evidence that "JS executed inside the web page" — and it’s exactly the one line hackers worldwide use when verifying an XSS vulnerability.

Why: if "I planted this one line on a forum and an alert box popped up on other people’s screens," that forum is broken into via XSS. Today you planted it only in your own file, but remember what this one line means.

3-5. DOM Manipulation — Changing the Screen with Code

Make js_dom.html.

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>DOM Manipulation</title></head>
<body>
  <p id="msg">original text</p>
  <script>
    let box = document.getElementById("msg");
    console.log("found content:", box.textContent);
    box.textContent = "changed text!";
    box.style.color = "red";
  </script>
</body>
</html>

Input: save → open → also watch F12’s Console tab.

Screen example: the screen shows red "changed text!", and the Console prints found content: original text. In the browser, console.log’s output goes not to the screen but to this Console tab.

How to read it: ① getElementById found the element with id="msg" and put it in box ② we read its content and printed it to the Console ③ we changed textContent to swap the on-screen text ④ we even changed the color with style.color. You’ve automated in four lines of code the edits you did with the mouse last time.

Why: "find element → read → change" — these three steps are all of DOM manipulation. Every flashy web app is ultimately a repetition of these three steps.

3-6. Events — A Button That Responds to Clicks

Make js_event.html.

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Click Counter</title></head>
<body>
  <button id="btn">Click me</button>
  <p id="count">clicks: 0</p>
  <script>
    let n = 0;
    let btn = document.getElementById("btn");
    btn.addEventListener("click", function() {
      n = n + 1;
      document.getElementById("count").textContent = `clicks: ${n}`;
    });
  </script>
</body>
</html>

Input: save → open → click the button several times.

Screen example: the number goes up by 1 with each click.

How to read it: addEventListener("click", function) is a reservation saying "when a click event happens, run this function." A function that waits for an event and then runs like this is called a callback ("call me later" function).

Why: the moment a static document becomes "a program that remembers state (the variable n) and responds to actions." You’ve just completed your first interactive app.

3-7. Predict — What If the script Goes on Top?

A prediction before the experiment. If you cut the <script> block from the code just now and move it to come before the button, what happens? ① Works fine ② The button doesn’t respond ③ The page doesn’t open.

Confirm yourself: move the script up, save, open — the page opens, but the button doesn’t respond. A red error sits in the Console tab:

Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')

This message’s structure reproduces identically in Node (verified 2026-09-09):

node -e "let btn = null; btn.addEventListener('click', function(){});"
TypeError: Cannot read properties of null (reading 'addEventListener')

How to read it: at the moment the script ran, the button element wasn’t yet created, so getElementById returned "nothing (null)," and calling addEventListener on null made it collapse. This error sentence — "cannot read something of null" — is the face you’ll meet most often in JS.

Why: an experiment teaching that a single execution order can decide an entire program, and that JS errors always remain in the Console tab. Build the habit that when JS acts strange, the first place to look is the Console.


4. Missions & Exercises

Mission — A Greeting Machine Mini App

Make greet.html meeting the requirements below.

  1. Place an <input id="name"> for entering a name, a "Greet" button, and a <p id="out"> to show the result
  2. When the button is pressed, read the input field’s value (inputVariable.value) and display "Nice to meet you, ○○!" in out
  3. If the input field is empty, display "Please enter a name" in red (if (condition) { ... } else { ... } — similar to Python)
  4. Each time it greets, record "greeted: ○○" in the Console
  5. Finally, write in your notes in one sentence why the fact that input values are "reflected as-is on screen" in your page is security-sensitive (hint: what if you could put HTML tags in the input?)

Exercises

Q1. State the difference between let and const, and what happens when you run const x = 1; x = 2;.

Q2. We use .value to read an input field’s value and .textContent to read a paragraph’s text. What’s the difference between the two?

Q3. Explain why "1" + 1 became 11 in 3-1, and why you need Number() to add two numbers read from input fields.

Q4. The error Uncaught TypeError: Cannot read properties of null (reading 'addEventListener') appeared. What situation is this, and what are two ways to fix it?


5. Model Answers & Completion Criteria

Mission Model Answer

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Greeting Machine</title></head>
<body>
  <input id="name" placeholder="Enter your name">
  <button id="greet">Greet</button>
  <p id="out"></p>
  <script>
    let btn = document.getElementById("greet");
    btn.addEventListener("click", function() {
      let name = document.getElementById("name").value;
      let out = document.getElementById("out");
      if (name === "") {
        out.textContent = "Please enter a name";
        out.style.color = "red";
      } else {
        out.textContent = `Nice to meet you, ${name}!`;
        out.style.color = "black";
        console.log(`greeted: ${name}`);
      }
    });
  </script>
</body>
</html>

How to verify: ① Does greeting with an empty input show the red notice? ② Does entering a name change it to the black greeting? ③ Is a record left in the Console? If all three are "yes," it’s complete.

Example model answer for sentence 5: "If input values are reflected on screen as-is, then when a user enters tags or scripts, those get reflected too, and someone else’s code can run on my page." — if this sentence was written, you’ve already arrived at XSS’s preface.

Exercise Solutions

Q1 solution. let is a variable you can refill; const is a constant that can’t be changed once set. Reassigning a const produces the error TypeError: Assignment to constant variable. (verified in Node, 2026-09-09).

Q2 solution. textContent reads "the text sandwiched between a tag pair," while value reads "the value a user typed into an input field." Tags like input, which have no between-an-open-and-close space, have no textContent, so we use value.

Q3 solution. Because in JS, + between a string and a number is concatenation, not addition. An input field’s .value always comes back as a string even if you type digits, so you must convert with Number(value) for real addition. Same idea as Python’s int().

Q4 solution. It means getElementById failed to find the element and returned null, and addEventListener was called on that null. Fixes: ① move the script to just before </body> so the element is created first, or ② check that the id written in getElementById and the actual tag’s id match (down to capitalization).

Completion Criteria Checklist

  • [ ] I can make variables with let and const and define functions with function
  • [ ] I can run JS in node or the Console tab and read console.log
  • [ ] I can find elements with getElementById and read and change textContent
  • [ ] I know the difference between an input’s value and textContent
  • [ ] I can make things respond to click events with addEventListener
  • [ ] I can move objects to and from strings with JSON.stringify/parse
  • [ ] Mission: I completed the greeting machine

6. Common Pitfalls & Fixes

Wall 1. The button does nothing when clicked

Symptom (reproduced and verified in Node, 2026-09-09):

TypeError: Cannot read properties of null (reading 'addEventListener')

Cause: nine times out of ten, the script ran before the element, or the id written in getElementById differs from the actual id (watch capitalization).
Fix: check F12 → the Console tab for a red error. The error tells you which line failed. Put script just before </body>.

Wall 2. The input field’s value comes out as undefined

Symptom: the value read shows the word undefined instead of the text you typed.
Cause: you found the element but omitted .value, or you found a non-input element. In JS, "a variable with no value assigned" becomes the value undefined with no error (verified 2026-09-09: printing let nothing; gives undefined).
Fix: read an input’s value as element.value. Text between tags is textContent; a value inside an input field is value.

Wall 3. Addition is weird (1+1 is 11)

Symptom (verified 2026-09-09): console.log("1" + 1)11. Number("1") + 12.

Cause: values read from input fields are not numbers but strings. + between strings is concatenation.
Fix: convert to a number with Number(value) before adding.

Wall 4. Backtick strings don’t work

Symptom: ${n} prints literally, unconverted.
Cause: you wrapped the string in single quotes (‘) instead of backticks (). ${} substitution works only in backtick strings. Fix: wrap with the backtick key, left of the number 1 key. Of the three kinds of quotes (', ", ), only backticks allow ${}.

Wall 5. It halts when I try to change a const

Symptom (verified 2026-09-09):

TypeError: Assignment to constant variable.

Cause: you tried to put a new value into a box made with const.
Fix: if the value changes, declare it with let from the start. If confused, follow the modern JS custom: "const by default, let when a change is needed."


7. Summary

Today’s Concepts

Concept One-line description
JavaScript The programming language that touches the DOM inside the browser
Node.js A tool that runs JS outside the browser (terminal) — browser counters like document are absent
script tag The engine room inside a page — place it just before </body>
Event/callback A function reserved in advance to run when an event (click, etc.) arrives
JSON A string format for exchanging data — pack with stringify, unpack with parse
null / undefined "looked, but absent" and "never assigned" — the regular protagonists of JS errors

Today’s Syntax/Commands

Syntax/command What it does
let x = 5; / const PI = 3.14; Make a variable / constant
function f(a) { ... } Define a function
console.log(x) Output (to the Console tab in the browser)
`the value is ${x}` Backtick string — the f-string equivalent
document.getElementById("msg") Find an element by id (browser only)
element.textContent / element.value Text inside tags / value inside an input field
element.addEventListener("click", function) Reserve a function for the click event
JSON.stringify / JSON.parse Object → string / string → object
node file.js Run JS in the terminal

The Instinct That Matters More Than Commands

Today’s core sense is always asking "who runs this code?" Even for the same JS, syntax experiments work anywhere, but document lives only in the browser. And flip what you learned today to the attacker’s view. ① alert ran = evidence of successful code injection. ② If you can read with getElementById = you can also read cookies and input values with JS. ③ If input values reflect on screen = if tags reflect, scripts can reflect too. Gather these three and you have XSS. For reference, besides textContent there’s also innerHTML for changing an element’s contents — this one inserts text interpreted as HTML. Code that reflects user input via innerHTML is a regular material for XSS — make "user input goes through textContent" your habit starting today.


Once every box is checked, Step 72 is complete. Click the checkbox in the sidebar to save your progress.