1. Values and Variables
Store text, numbers and true/false, and print them: your first lines of code.
Chapter film (about 7m) is coming. The written chapter below is complete.
Variables, Constants & Type System
In plain English. A variable is a labelled box that holds a value, such as a username, a price, or how many rows a table shows. Your tests are full of them: the test data you type, the text you read back, the count you expect. let makes a box whose contents you can swap later. const makes a box whose label is glued to one value. Use const unless you know the value will change, because a value that can't change is one less thing to go wrong. Every value also has a type, the kind of thing it is: text (a string), a number, or true/false (a boolean). Below, a binding just means the link between a name and its value.
Use let for a binding you intend to reassign and const for one you do not. Note carefully what const guarantees: the binding cannot be reassigned. It does not freeze the value. const user = { name: 'Alice' }; user.name = 'Bob'; is perfectly legal — only user = {} throws a TypeError. The legacy keyword var exists but should be avoided: it is scoped to the enclosing function rather than the enclosing block, so a var declared inside a loop or an if is still readable after it.
JavaScript is a dynamically typed language. This means variables do not have types; values have types. let x = 5; x = "hello"; is perfectly valid. There is no compile step, so nothing catches a type mistake before the line runs. To check the type of a value at runtime, JavaScript provides the typeof operator.
JavaScript has a small set of primitive types: string, number, boolean, null, undefined, symbol, and bigint. Notice there is no distinction between integers and floating-point numbers; everything is a number (a double-precision 64-bit float). bigint was introduced later for arbitrarily large integers.
null and undefined both represent emptiness, and they are separate values. A variable that has been declared but never assigned is undefined, and so is a missing object property or the return value of a function that returns nothing. null is a value you assign deliberately to mean the intentional absence of any object value.
let mutableVar = 10;
console.log('Initial mutableVar:', mutableVar, 'Type:', typeof mutableVar);
mutableVar = "Now I am a string!";
console.log('Reassigned mutableVar:', mutableVar, 'Type:', typeof mutableVar);
const constantBinding = 42;
// constantBinding = 43; // TypeError: Assignment to constant variable.
// const freezes the binding, NOT the value:
const settings = { retries: 2 };
settings.retries = 5; // allowed - we mutated the object, not the binding
// settings = { retries: 5 }; // TypeError - this reassigns the binding
console.log('const object mutated:', settings);
var legacyVar = true; // Avoid using var
let uninitialized;
let explicitlyEmpty = null;
console.log('uninitialized:', uninitialized);
console.log('explicitlyEmpty:', explicitlyEmpty);
const bigIntNum = 9007199254740991n;
console.log('bigIntNum:', bigIntNum, 'Type:', typeof bigIntNum);Sign in to track your progress
Strings In-Depth
In plain English. A string is a piece of text: a username, an error message, the heading on a page. Most of what a tester checks on a page is text read back and compared, so you will handle strings constantly. This lesson covers the everyday tools: trimming stray spaces, checking whether text contains a word, splitting a sentence into parts, and slotting a value into a message, which is called interpolation. Strings are immutable, meaning they never change once made; every string method hands you a new string and leaves the original alone. A regular expression, or regex, is a pattern that describes text instead of spelling it out exactly, useful when part of the text changes from run to run.
JavaScript strings can be enclosed in single quotes ('...'), double quotes ("..."), or backticks (`...`). The backtick syntax creates what are called Template Literals. Template literals allow for multi-line strings and string interpolation, embedding expressions directly into strings using ${expression}.
Strings in JavaScript are immutable. Once a string is created, it cannot be changed. String methods always return a new string rather than modifying the original in place.
JavaScript provides a rich set of built-in methods on the String prototype. You have includes(), startsWith(), endsWith() for boolean checks. For manipulation, split(), trim(), replace(), slice(), and substring() are frequently used. Note that slice() can take negative indices to count from the end of the string.
Regular expressions are deeply integrated into JavaScript. You can create a regex literal simply by enclosing the pattern in forward slashes, e.g., /pattern/g. You can use the test() method on a regex object to check for a match, or the match(), replace(), and search() methods directly on a string object. One trap to know before you meet it in a test script: a regex literal carrying the g flag is stateful. test() and exec() on a global regex start from its lastIndex property and advance it, so calling the same global regex object twice in a row alternates true, false, true, false. Use a non-global regex for boolean checks, or build a fresh one each time.
const name = 'Alice';
const greeting = `Hello, ${name}!
Welcome to JavaScript.`; // Multi-line and interpolation
console.log(greeting);
const text = " JavaScript is awesome! ";
console.log('Trimmed:', text.trim());
console.log('Includes "Script":', text.includes('Script'));
console.log('StartsWith "Java":', text.trim().startsWith('Java'));
const parts = text.trim().split(' ');
console.log('Split into words:', parts);
const sliced = text.slice(-8, -2);
console.log('Sliced with negative indices:', sliced);
// Regex
// No `g` flag here: test() on a global regex advances lastIndex and
// would return true, false, true, ... on repeated calls.
const regex = /is/;
console.log('Regex test:', regex.test(text)); // true
console.log('Regex test again:', regex.test(text)); // true (still true - not global)
console.log('String match:', text.match(/a/g)); // Find all 'a's
console.log('Replace:', text.replace(/awesome/, 'fantastic'));Sign in to track your progress
Numbers & Type Coercion
In plain English. Numbers turn up in testing more than you might expect: a cart total, a count of search results, a price you read off the page as text and need to do sums with. This lesson shows how JavaScript does arithmetic, how to turn text such as "10.5" into a real number, and the odd values you get when a calculation fails. It also covers comparing values. Coercion means JavaScript quietly converting a value from one type to another, such as text to a number, before comparing; that habit causes bugs, so you will use the strict comparison ===, which does not convert. Truthy and falsy describe whether a value counts as true or false when used as a yes/no check.
JavaScript has a single numeric type for ordinary arithmetic: Number, a double-precision 64-bit IEEE 754 float. There are no separate integer and floating-point types, so you don't have to worry about integer division truncation (e.g., 5 / 2 is 2.5, not 2), but you do have to be careful with floating-point precision issues: 0.1 + 0.2 evaluates to 0.30000000000000004, so 0.1 + 0.2 === 0.3 is false. Compare floats against a small tolerance instead of with ===.
To convert strings to numbers, JavaScript provides parseInt() and parseFloat(). It also has special numeric values: NaN (Not-a-Number) and Infinity. NaN is returned when a mathematical operation fails (like dividing a string by a number). A quirky characteristic of NaN is that it doesn't equal itself (NaN === NaN is false); you must use Number.isNaN() to check for it safely.
For mathematical operations beyond the arithmetic operators, JavaScript provides the Math object. It contains static properties like Math.PI and static methods like Math.round(), Math.floor(), Math.ceil(), and Math.random().
JavaScript has two equality operators: loose equality (==) and strict equality (===). Loose equality performs type coercion before comparing (e.g., 1 == '1' is true). This often leads to unexpected bugs. Always use strict equality (=== and !==), which checks both value and type. Furthermore, JS uses "truthy" and "falsy" concepts in boolean contexts. false, 0, -0, 0n (the BigInt zero), "", null, undefined, and NaN are falsy; everything else is truthy — including "0", "false", the empty array [], and the empty object {}. That last pair catches people out: if ([]) runs its body.
const a = 5;
const b = 2;
console.log('Division:', a / b); // 2.5, no integer truncation
const parsedInt = parseInt("10.5", 10);
const parsedFloat = parseFloat("10.5");
console.log('parseInt:', parsedInt, 'parseFloat:', parsedFloat);
const notANumber = "hello" / 2;
console.log('Is NaN?', Number.isNaN(notANumber));
console.log('Infinity:', 1 / 0);
console.log('Math.round(4.7):', Math.round(4.7));
console.log('Math.random():', Math.random());
// Equality and Coercion
console.log('1 == "1":', 1 == '1'); // true (coercion)
console.log('1 === "1":', 1 === '1'); // false (strict)
// Truthy/Falsy
if ("") {
console.log('This will not print');
}
if ("hello") {
console.log('Non-empty strings are truthy');
}Sign in to track your progress
Practice
3 exercises attached to this chapter, about 12m.