Labelled boxes for your to-do app
In Level 1 you typed JavaScript into the browser console and saw it answer you straight away. Now we'll make it remember things. Every to-do app needs some starting data: a title, how many tasks there are, whether the list is finished. JavaScript keeps data like this in variables.
Think of a variable as a labelled box. The label is the name, such as taskCount, and the box holds a value, such as 0. Later in your code you use the label to get the value back out.
Modern JavaScript gives you two ways to make a box:
const: a box that is sealed once you fill it. You can't put a different value in it.let: a box you can reopen and fill with a new value later.
The habit most experienced engineers follow is to use const by default and switch to let only when the value really has to change. When you read code months later, every const tells you that this name always means the same thing, and that makes bugs easier to find.
Walkthrough: the to-do app's first data
Open DevTools (F12, or Cmd+Option+J on a Mac) and go to the Console tab. Type these lines one at a time:
// The app's title never changes, so we use const
const appTitle = "My To-Do List";
// The number of tasks will go up as the user adds tasks, so we use let
let taskCount = 0;
// Is every task done? Right now, no.
let allDone = false;
// Read the values back by typing their names
console.log(appTitle); // My To-Do List
console.log(taskCount); // 0
Now suppose the user adds a task. Because taskCount was made with let, we can reassign it, which means giving the same name a new value:
taskCount = 1; // no keyword this time: the box already exists
console.log(taskCount); // 1
Notice that you write let only once, when the variable is created. After that you use the name on its own.
What happens when you reassign a const
Try changing the title:
appTitle = "Shopping List";
// Uncaught TypeError: Assignment to constant variable.
That error is the whole point of const. JavaScript refuses the reassignment and throws a TypeError. If your code expects the title never to change, you want a loud error at the exact line that tries to change it, not a quiet bug that turns up three screens later.
A second rule: a const must get its value when you create it.
const dueDate;
// Uncaught SyntaxError: Missing initializer in const declaration
Gotcha:
conststops you from reassigning the name. It doesn't freeze everything inside. When you meet objects and arrays in later levels, you'll find you can still change their contents inside aconst. For now, remember thatconstmeans "this label always points at the same value".
The basic value types
Every value has a type. Five types you will use all the time are primitives, the simplest building blocks:
| Type | Example | What it means for our app |
|---|---|---|
| string | "Buy milk" |
Text, such as a task's name |
| number | 3 or 4.5 |
Counts and amounts |
| boolean | true / false |
Yes or no: is the task done? |
| undefined | undefined |
"No value has been given yet" |
| null | null |
"Deliberately empty" |
(JavaScript has two more primitives, bigint and symbol, but you won't need them for a while.)
The typeof operator tells you a value's type, and its answer is always a string:
const firstTask = "Buy milk";
let isDone = false;
let dueDate; // declared with let but given no value
let assignedTo = null; // we chose to leave this empty
console.log(typeof firstTask); // "string"
console.log(typeof taskCount); // "number"
console.log(typeof isDone); // "boolean"
console.log(dueDate); // undefined
console.log(typeof dueDate); // "undefined"
console.log(typeof assignedTo); // "object" <- surprise!
Gotcha:
typeof nullgives"object". This is a known quirk from JavaScript's earliest version, and it can't be fixed without breaking old websites. Remember it, because it trips up even experienced developers.
How do undefined and null differ? JavaScript itself uses undefined for "nothing here yet". You write null yourself when you want to say "empty on purpose", for example a task that isn't assigned to anyone.
Why not var?
In older tutorials and on Stack Overflow you will see a third keyword, var. It still works, but modern code avoids it because it is too forgiving:
var count = 5;
var count = 10; // no error: the first one is silently replaced
console.log(count); // 10
let total = 5;
let total = 10;
// Uncaught SyntaxError: Identifier 'total' has already been declared
There are two other problems. A var ignores the curly-brace blocks { } that let and const respect, so it can leak out of places where you meant to keep it. And you can use a var before the line that creates it and get undefined back instead of an error. Each of these turns a mistake that should fail loudly into one that fails quietly. When you read old code, recognise var. When you write new code, don't use it.
Console tip: Chrome's console lets you run
letagain for the same name across separate entries, which makes experimenting easier. Inside a real script file, the redeclaration error above still applies.
Check it works
Paste this into the console:
const appTitle2 = "My To-Do List";
let taskCount2 = 0;
taskCount2 = 2;
console.log(appTitle2, taskCount2, typeof taskCount2);
// Expected: My To-Do List 2 number
If you see My To-Do List 2 number, your variables work. Now try appTitle2 = "x" and confirm that you get a TypeError.
Key takeaways
- Use
constby default. Useletonly for values that must be reassigned, such astaskCount. - Reassigning a
constthrows aTypeError, and aconstmust be given a value when you create it. - The everyday primitive types are string, number, boolean, undefined and null. Check them with
typeof. typeof nullreturns"object". It's a historical quirk, not a sign that null is an object.- Avoid
var: it allows silent redeclaration, ignores blocks, and lets you use a variable before it is created.