Indexing, Slicing & Immutability

Beginner · 18 min read · ▶ live playground · ✦ checkpoint

The string "Mina" looks like four tiny pieces, but JavaScript will not let you edit those pieces in place. You can read them, copy a range of them, and build a new string from them. That is the whole trick: inspect the sealed token, then make a new one.

Indexes start at zero

An index is a position number used to read one piece from a string. JavaScript uses zero-based indexing, which means the first position is 0, not 1.

Think of an index as "steps from the start." Zero steps from the start lands on the first character. One step lands on the second.

const playerName = "Mina";
 
console.log(playerName[0]);
console.log(playerName[1]);
console.log(playerName[2]);
console.log(playerName[3]);
console.log(playerName[4]);

M, i, n, a, then undefined.

The last line asks for a position that does not exist. JavaScript gives you undefined, the "no value here yet" primitive you met in lesson 2.2.

This is not counting for humans. It is addressing for the engine. The first character is not "character one" to JavaScript. It is "the character zero steps from the start."

Reading from the end with .at()

Bracket indexing reads nicely from the front, but grabbing the last character with brackets is awkward:

const secretCode = "R7K9";
 
console.log(secretCode[0]);
console.log(secretCode[secretCode.length - 1]);
console.log(secretCode[-1]);
console.log(secretCode.at(-1));
console.log(secretCode.at(-2));

R, 9, undefined, 9, then K.

.at() is a method, a command you call with a dot. With positive numbers, it acts like brackets: secretCode.at(0) reads the first character. With negative numbers, it counts from the end: .at(-1) reads the last character, .at(-2) reads the one before it.

Notice the trap in the middle: secretCode[-1] does not mean "last character." Brackets do not count backward for strings. Use .at(-1) when you mean the end.

Extracting with slice()

A substring is a smaller string pulled out of a larger string. slice() extracts a substring without mutating the original string. Mutate means change a value in place.

slice(start, end) starts at the first index and stops before the second index. The start is included. The end is excluded.

const ticket = "VIP-042-Mina";
 
const ticketType = ticket.slice(0, 3);
const ticketNumber = ticket.slice(4, 7);
const playerName = ticket.slice(8);
const lastFour = ticket.slice(-4);
 
console.log(ticketType);
console.log(ticketNumber);
console.log(playerName);
console.log(lastFour);
console.log(ticket);

VIP, 042, Mina, Mina, then VIP-042-Mina.

The missing second argument in ticket.slice(8) means "keep going to the end." The negative start in ticket.slice(-4) means "start four positions from the end."

Read the second number as a stop sign, not as a character you get to keep. ticket.slice(4, 7) starts at index 4, then stops before index 7, so it returns the characters at indexes 4, 5, and 6: "042".

An off-by-one error is a bug where your count misses by one position. Most slice mistakes come from treating the end index as included. Say "stop before" out loud until it sticks.

String has a few extraction methods. You may meet substring() in existing code, but slice() is the one to practice first because it reads cleanly from both directions.

Try it - read a player tag

Run this, then change tag to "MOD-105-Jules". Keep predicting before you run: which pieces change, and which piece stays the original?

javascript — live consolereal engine
⌘/Ctrl + Enter to run

Methods return results, not edits

Strings are immutable sealed tokens. A string method can inspect a string and return a result, but it cannot rewrite the old string.

That catches beginners because method calls can look like commands:

let chant = "go team";
 
chant.slice(0, 2);
console.log(chant);
 
const shortChant = chant.slice(0, 2);
console.log(shortChant);
 
chant = chant.slice(0, 2);
console.log(chant);

go team, go, then go.

The first slice() call returns "go", but the code does not store that return value anywhere. The chant label still points at the old string. The final line works because reassignment moves the label to the new string.

That rule will matter constantly in the next lesson. Methods that create changed text return new strings. They do not change the original string behind your back.

You can now read one piece, read from the end, and extract a smaller string while keeping the original sealed token intact. Next, you'll use those same rules with everyday string methods and a cleaner way to build messages.

Checkpoint

Answer all three to mark this lesson complete

+50 XP on completion