Strings
Create JavaScript text with quotes and template literals, use escape sequences, read characters by index, and understand why strings are immutable.
- 01Write textChoose single quotes, double quotes, or backticks, and use a backslash for special characters.
- 02Read charactersUse
length, index numbers, andat(-1)without being off by one. - 03Make new stringsJoin text with
+,+=, and template literals, and know that a string itself can't be changed.
Watch the video lectures
Full course on YouTube (opens in a new tab) ↗- Lecture 14Strings, part 1Watch on YouTube (opens in a new tab) ↗
- Lecture 15Strings, part 2Watch on YouTube (opens in a new tab) ↗
Strings are JavaScript text
A string is a value that holds text. Names, messages, file paths, and button labels are all strings. The answer that prompt gives back is a string too.
A string is a primitive value. You met primitives in the Data types lesson: simple values like numbers and strings. A string can't be changed after it is made. You'll see what that means later in this lesson.
You have already seen one surprise with strings. In Why JavaScript?, "5" + 3 gives "53", not 8. This lesson explains the text side of that rule. The Type conversion lesson, later, gives the full set of rules.
A string is text: characters in a row. You write it between quotes or backticks. Each character has a position number, starting at 0. To change the text, you make a new string.
Picture the text as beads on a necklace. Each bead is one character. The first bead is number 0, the next is number 1, and so on. You can point at one bead, or count all the beads. To get different beads, you make a new necklace.
- In real life: The whole necklace
- In JavaScript: The whole string, like
"cat" - In real life: One bead
- In JavaScript: One character, like
word[0] - In real life: Numbering the beads, starting at 0
- In JavaScript: Position numbers, starting at 0
- In real life: Counting all the beads
- In JavaScript:
word.length
The lesson goes in this order:
- Quotes and template literals: three ways to write a string.
- Escape sequences: how to put special characters inside a string.
- Length and indexes: how to count and read characters.
- Why a string can't be changed.
- Concatenation: how to join strings.
Later lessons go deeper: String methods, Template literals & tagged templates, Unicode & string internals, and Comparing & sorting text.
Quotes & template literals
STEP THROUGHA string written straight into your code is called a string literal. You can write one in three ways:
- Single quotes:
'hello' - Double quotes:
"hello" - Backticks:
`hello`
Single quotes and double quotes make exactly the same kind of string. Pick the one that is easier to read. Backticks make a template literal. A template literal can go over several lines. It can also have blanks, written ${...}, that JavaScript fills with a value.
The table compares the three ways. Read each row as: "when I write it like this, it is good for this."
| How you write it | Example | When to use it |
|---|---|---|
| Single quotes | 'hello' | Short text that has no apostrophe in it. |
| Double quotes | "I'm learning" | Text that has an apostrophe, like I'm. |
| Backticks | Hi, ${name} | Text with blanks to fill, text on several lines, or a sum like ${price * qty}. |
const name = "Asha";console.log("Hi, ${name}!");console.log(`Hi, ${name}!`);Line 1 stores the text Asha in name. Line 2 uses double quotes. So it prints the characters Hi, ${name}! exactly as written. Line 3 uses backticks. So JavaScript fills the blank and prints Hi, Asha!.
${name} is just six letters and signs. In backticks, it is a blank that JavaScript fills with the value of name.Think of a paper form with blanks. The fixed words are already printed on it. JavaScript fills each blank by working out the code inside ${...}.
- In real life: A blank marked name
- In JavaScript:
${name} - In real life: A blank that asks for a sum
- In JavaScript:
${price * qty} - In real life: The filled-in form
- In JavaScript: The finished string
The replay below builds the same sentence in two ways. Line 5 uses a template literal. Line 6 joins pieces with +. Pick a different person. Then guess: do lines 7 and 8 still print the same text?
Guess: will line 7 and line 8 print the same text? Then step through each way of writing a string.
script
const age = 12;const single = 'A string can use single quotes.';const double = "Double quotes make apostrophes easy: I'm learning.";const template = `Hi, ${name}. Next year you will be ${age + 1}.`;const same = "Hi, " + name + ". Next year you will be " + (age + 1) + ".";console.log(template);console.log(same);Backticks are often easier to read for sentences. Each value sits right where it appears in the sentence. Joining with + is still useful for short pieces, and for adding to a string bit by bit.
const name = "Asha";const message = `Hello, ${name}!Your tea is ready.`;console.log(message);Line 1 stores a name. Line 2 has one template literal that goes over two lines. The line break is part of the string. So the console prints Hello, Asha! on one line and Your tea is ready. on the next.
Escape sequences
INTERACTIVESome characters are hard to put inside a string. A quote mark would end the string too early. A line break can't go inside single or double quotes.
An escape sequence solves this. It is a backslash, \, followed by a letter or sign. The backslash says: "don't read the next character in the normal way." For example:
\nmeans "start a new line here".\"means "put a double quote mark here", instead of ending the string.
Each row of the table shows one escape sequence, what it puts in the string, and an example.
| You write | You get | Example |
|---|---|---|
\n | A new line | "Line 1\nLine 2" |
\t | A tab, a wide space | "Name\tScore" |
\\ | One backslash | "C:\\notes" |
\' | A single quote | 'It\'s ok' |
\" | A double quote | "She said \"hi\"" |
\` | A backtick | `Use \`code\`` |
\u{1F600} | A 😀 character | "Smile: \u{1F600}" |
Step through real escape sequences. In the first output, the two characters \n become a real line break.
script
console.log("Name\tScore");console.log("She said \"hi\"");console.log("C:\\notes");console.log("Smile: \u{1F600}");Use an escape when it makes the string easier to write. If the backslashes get hard to read, switch to another quote style. For example, "It's ok" is easier to read than 'It\'s ok'.
console.log("Line 1\nLine 2");console.log("Line 1\\nLine 2");Line 1 has \n, so its output has a real line break. Line 2 has \\n. The first backslash escapes the second one. So the output shows a backslash and the letter n: \n. You need this when you want to show a backslash itself, for example in a Windows file path.
Length & indexes
INTERACTIVEThe characters in a string are in a fixed order. Each one has a position number, called an index. The first index is 0, not 1.
text.lengthtells you how many positions the string has.text[0]reads the first character. The square brackets hold the index.text[text.length - 1]reads the last character, if the string isn't empty.
Type your own text into the inspector below. It shows each character with its index.
const text = "JavaScript";console.log(text.length);console.log(text[0]);console.log(text.at(-1));console.log(text[99]);The text has length 10. Index 0 holds J. The last index is length - 1. Index 99 gives undefined.
If you ask for an index that doesn't exist, JavaScript gives undefined. That is JavaScript's word for "no value here". It gets its own lesson soon after this one.
const word = "tea";console.log(word.at(-1));console.log(word[word.length]);tea has length 3. So its indexes are 0, 1, and 2.
- Line 2 uses
at(-1).at()is a method: a built-in action you call on a string with a dot. It reads one position.-1means "one back from the end", so it printsa. - Line 3 asks for index 3. That is one past the end, so it prints
undefined.
word[3] gives undefined.Use at(-1) when you mean "the last character". If the string might be empty, check for that first.
const text = "";console.log(text.length);console.log(text[0]);console.log(text.at(-1));Line 1 makes an empty string: two quote marks with nothing between them. It has no characters. Line 2 prints 0. Lines 3 and 4 both ask for a character that isn't there, so each prints undefined. Before you read the first or last character, check that the string isn't empty.
Try 😀 in the inspector. "😀".length is 2, not 1. JavaScript stores text in small pieces called UTF-16 code units, and length counts those pieces. Most letters take one piece. Some emoji take two. This is how strings really work, not a mistake. The Unicode & string internals lesson explains it.
Strings can't be changed
STEP THROUGHOnce a string is made, you can't change its characters. We say strings are immutable, which means "can't be changed". You can't edit one letter in place.
A variable can still hold a different string later. The old string stays as it was.
Picture a word carved into a stone, with a name label tied to it. The label says word, and the stone says "cat". You can't scratch out just the first letter. Instead, you carve a new stone that says "bat". Then you move the word label to the new stone.
- In real life: A word carved into a stone
- In JavaScript: The string value
"cat" - In real life: Trying to scratch out one letter
- In JavaScript:
word[0] = "b" - In real life: Carving a new stone
- In JavaScript:
"b" + word.slice(1) - In real life: Moving the name label to the new stone
- In JavaScript:
word = ...
Here is a change that looks right but doesn't work. This code runs without strict mode:
let word = "cat";word[0] = "b";console.log(word);Line 2 tries to change the first letter to b. JavaScript quietly ignores it. So line 3 prints cat.
Strict mode is a stricter set of JavaScript rules. You turn it on with the line "use strict" at the top. JavaScript modules always use it. In strict mode, the same change throws a TypeError instead of being ignored:
"use strict";let word = "cat";word[0] = "b";console.log(word);Line 1 turns on strict mode. Line 3 throws a TypeError, so line 4 never runs.
Here is the right way. Make a new string, then put it in the variable. word.slice(1) copies every character from index 1 to the end, so it gives "at". Step through the replay to see it.
This replay shows only the right way: make a new string, then store it in the variable.
script
word = "b" + word.slice(1);console.log(word);"cat". On the right, JavaScript makes a brand-new string, "bat", and puts it in the box. The old "cat" was never changed.const name = "asha";const loudName = name.toUpperCase();console.log(name);console.log(loudName);toUpperCase() is a method that gives back the text in capital letters.
- Line 2 makes a new uppercase string and stores it in
loudName. - Line 3 still prints
asha, because the original string didn't change. - Line 4 prints
ASHA.
String methods work this way: they give back new text. Save the result in a variable when you need it.
slice appears hereThis lesson doesn't teach string methods yet. We use slice(1) only to copy "everything after the first character". The String methods lesson covers it fully.
Joining strings
STEP THROUGHConcatenation means joining strings end to end. The + sign joins when either side is a string.
+= is a short way to add more text to the end of a variable. message += "hi" means the same as message = message + "hi".
The replay below uses a loop: lines 2 to 4 run line 3 three times, with i as 1, then 2, then 3. Each time, line 3 adds one more piece to message.
Watch += build a string, then compare the two Total lines.
script
for (let i = 1; i <= 3; i = i + 1) { message += "#" + i + " ";}console.log(message);console.log("Total: " + 2 + 3);console.log("Total: " + (2 + 3));let list = "";list += "tea";list += ", milk";console.log(list);Line 1 starts list as an empty string. Lines 2 and 3 each make a longer string and put it back in list. The output is tea, milk. This is fine for a few pieces. For a list that keeps growing, the Arrays lesson shows a better way.
Watch the order. In "Total: " + 2 + 3, JavaScript works from left to right:
- It starts with text, so the first
+joins:"Total: 2". - The second
+also has text on its left, so it joins again:"Total: 23".
To add the numbers first, put round brackets around the sum. "Total: " + (2 + 3) gives "Total: 5".
+ joins: first 2, then 3. On the right, the round brackets make 2 + 3 happen first, so 5 is joined.Long lists of pieces are often kept in an array and joined with join(""). Arrays and String methods get their own lessons later. For now, use +, +=, and template literals.
Where you’ll use this
Strings appear whenever code shows text to people or sends text to other programs. You'll use them to:
- make labels for buttons and messages,
- read what people type into a form,
- build web addresses,
- print messages while you look for bugs,
- put values into text on the page.
const user = "Ada";const unread = 3;const label = `${user} (${unread} new messages)`;console.log(label); const path = "/users/" + user;console.log(path);Lines 1 and 2 store a name and a count of unread messages. Line 3 builds a label with a template literal. So the first log prints Ada (3 new messages).
Line 6 joins two short pieces with +. The second log prints /users/Ada. This is a path: the part of a web address after the site name.
The table shows a good first choice for four everyday jobs. Read each row as: "for this job, start with this, because…"
| What you need | A good first choice | Why |
|---|---|---|
| A button label that never changes | A plain string, like "Save" | There is no value to put in, so just write the text. |
| A name inside a sentence | A template literal, like Hello, ${name}! | The sentence stays easy to read around the name and the punctuation. |
| A path made of a fixed start and an ID | "/users/" + userId | Two short pieces join directly. Put the slash at the end of the fixed start. |
| A sum inside a sentence | A template literal with ${price * quantity} | JavaScript works out the sum first, then puts the answer into the text. |
Template literals read like sentences. + is fine for short pieces, like a path. Remember that prompt always gives back a string.
A path usually uses an ID: a short code for a person that never changes. It doesn't use the name people see, because a name can change.
const userId = "asha";const profilePath = "/users/" + userId;console.log(profilePath);Line 1 stores the ID asha. Line 2 joins the fixed start of the path, /users/, and that ID. The log prints /users/asha. A website could use this path to open Asha’s profile page.
const userId = "Asha Khan";const profilePath = "/users/" + encodeURIComponent(userId);console.log(profilePath);Line 1 has a space in the value. A web address can't hold a plain space.
Line 2 uses encodeURIComponent. It is a built-in function that makes one piece of text safe for a web address. It turns the space into %20. So the console prints /users/Asha%20Khan.
Use an ID when you have one. When any other value must go into a web address, encode it first.
const drink = "tea";const price = 3;const summary = `Your ${drink} costs $${price}.`;console.log(summary);Lines 1 and 2 store the values that can change. Line 3 puts both values into a sentence. The first $ on line 3 is just a dollar sign. Only ${...} makes a blank. The console prints Your tea costs $3.
Template literals help when words, spaces, and values must stay in the right order.
A string is just text. Building a label or a path doesn't run the text as code. Later, the Browser security model lesson explains extra rules for putting text from outside into a web page.
A good habit: start with the smallest piece of text and print it. Then add one value at a time. This makes mistakes easy to see, like a missing space, a wrong slash, or a + that joins when you wanted it to add.
Common mistakes
“Single quotes and double quotes make different types.”
They make the same type: a string. The only difference is which quote mark you need to escape inside.
“Indexes start at 1, like when people count.”
String indexes start at 0. The last index is length - 1.
“Changing word[0] changes the string.”
It doesn't. Without strict mode, JavaScript ignores it. In strict mode, it throws an error. Make a new string instead.
“+ always adds numbers.”
If either side is a string, + joins. Put round brackets around a sum you want worked out first.
“length always counts the letters you see.”
For plain English text, it does. Some emoji and joined characters count as more than one. The Unicode lesson explains why.
A syntax error means JavaScript can't read the code, so it doesn't run any of it. Quote marks in the wrong place cause many syntax errors.
'It's fine'"It's fine"`It's fine`'Say \"hi\"'"hello'line 1 line 2'
Sort each line of code. Will JavaScript read it as a string, or stop with a syntax error? Each answer explains how the quote marks decide it.
Practice: strings
6 EXERCISESGuess the four lines the console prints.
const text = "Hi!";
console.log(text.length);
console.log(text[0]);
console.log(text[text.length - 1]);
console.log(text[99]);length is 3. Index 0 is H. length - 1 is 2, so the last character is !. Index 99 has no character, so it prints undefined.
Read the code. Type the exact sentence it prints.
const name = "Ada";
const place = "console";
console.log(`Hello, ${name}! Welcome to the ${place}.`);const name = "Ada";
const place = "console";
console.log(`Hello, ${name}! Welcome to the ${place}.`);The template literal fills the two blanks. So the console prints Hello, Ada! Welcome to the console.
What text does this program print?
console.log("She said \\"JavaScript!\\"");console.log("She said \\"JavaScript!\\"");The backslashes stop the inner double quotes from ending the string. The backslashes themselves don't appear in the output.
Rewrite the code so it prints bat.
let word = "cat";
word[0] = "b";
console.log(word);let word = "cat";
word = "b" + word.slice(1);
console.log(word);Strings can't be changed. So the fix makes a new string, bat, and stores it in the variable word.
Guess the exact output.
console.log("Total: " + 2 + 3);First, "Total: " + 2 becomes "Total: 2". Then + 3 joins again. So the output is Total: 23.
A profile button needs the path to Asha’s page. Read the program. Type the exact path it prints.
const userId = "asha";
const profilePath = "/users/" + userId;
console.log(profilePath);const userId = "asha";
const profilePath = "/users/" + userId;
console.log(profilePath);The path starts with /users/. Then + adds the ID asha. So the path is /users/asha.
Quiz: check your understanding
8 QUESTIONSQuestion 1 of 8Which way of writing a string lets
${name}fill in a value?Choose an answer to see the explanation.
Question 2 of 8What length does this print?
Read the code, then predictconst word = "cat"; console.log(word.length);Choose an answer to see the explanation.
Question 3 of 8What character does this print?
Read the code, then predictconst word = "cat"; console.log(word[0]);Choose an answer to see the explanation.
Question 4 of 8What does
\nmean inside a string in quotes?Choose an answer to see the explanation.
Question 5 of 8This script runs without strict mode. What does it print?
Read the code, then predictlet word = "cat"; word[0] = "b"; console.log(word);Choose an answer to see the explanation.
Question 6 of 8What does this print?
Read the code, then predictconsole.log("Total: " + 2 + 3);Choose an answer to see the explanation.
Question 7 of 8Which code reads the last character of a string named
textthat isn't empty?Choose an answer to see the explanation.
Question 8 of 8What does this empty-string code print?
Read the code, then predictconst text = ""; console.log(text.at(-1));Choose an answer to see the explanation.
Key takeaways
- A string holds text. You write it with single quotes, double quotes, or backticks.
- Backticks make a template literal. Each
${...}is a blank that JavaScript fills with a value. - Escape sequences put special characters in a string:
\nfor a new line,\tfor a tab,\"for a double quote. lengthcounts the positions. Indexes start at 0. An index with no character givesundefined.- Strings can't be changed. To change the text, make a new string and store it in the variable.
+and+=join strings. Put round brackets around a sum you want worked out first.
Remember the one-liner.
A string is text that can't be changed: write it with quotes or backticks, count positions from 0, and make a new string when the text needs to change.
Up next: Booleans & truthiness, then undefined and null.