Skip to content

Strings

docs.scrimba.com

You are building a greeting for a signed-in user, and you have their name sitting in a variable. You need the page to say "Welcome back, Priya" without you typing "Priya" by hand, because tomorrow it is Kwame, and the day after that it is someone you have never heard of. Text you can build, measure, and reshape on the fly is a string, and this chapter is about working with them.

Making strings

A string is text: any run of characters wrapped in quotes. You can use single quotes or double quotes, and they behave the same way, so pick one and stay consistent.

js
const firstName = "Priya";
const greeting = "Welcome back";

The most useful way to build a string is a template literal, written with backticks instead of quotes. Inside a template literal you can drop a value into the text with ${...}, and JavaScript fills in whatever that value holds:

js
const firstName = "Priya";
const message = `Welcome back, ${firstName}`;
console.log(message); // Welcome back, Priya

That ${firstName} is a slot. When the string is built, the slot is replaced by the value of firstName. Reach for template literals whenever you are building text out of pieces.

A string is a value made of text. Single quotes and double quotes produce identical strings, so the choice between them is about style and about which quote character you need to include: "it's here" avoids escaping, and so does 'she said "hi"'.

The form to prefer is the template literal, a string written with backticks. It does two things ordinary quotes cannot. It interpolates values with ${...}, dropping the result of any expression straight into the text, and it can span multiple lines without a special escape:

js
const firstName = "Priya";
const itemCount = 3;
const message = `Welcome back, ${firstName}. You have ${itemCount} items waiting.`;
console.log(message); // Welcome back, Priya. You have 3 items waiting.

Anything that produces a value can go in the slot, not only variable names, so ${itemCount} could equally be ${itemCount + 1}. Building text with ${...} reads far cleaner than gluing pieces together with quotes and plus signs, which is why it is the default.

A string is JavaScript's text primitive: one of the language's basic value types, alongside numbers and booleans (see data types for the full set). Single and double quotes are interchangeable and produce the exact same value; the only real decision they force is which quote character you would otherwise have to escape.

The form worth defaulting to is the template literal, delimited by backticks. It interpolates any expression with ${...}, evaluating what is inside and coercing the result to a string, and it preserves literal newlines so multi-line text needs no \n:

js
const firstName = "Priya";
const itemCount = 3;
const summary = `Hi ${firstName}, you have ${itemCount} items and ${itemCount === 1 ? "it is" : "they are"} waiting.`;
console.log(summary); // Hi Priya, you have 3 items and they are waiting.

The slot holds an expression, not only a name, so arithmetic, method calls, and comparisons all work inside it. That expressiveness is why interpolation beats concatenation for anything past a two-part string: the shape of the final text stays readable in the source. The one habit to build is reaching for backticks by default and dropping to plain quotes only for a fixed, single-piece string where interpolation buys you nothing.

JunoMaking strings A string is text in quotes, and single or double quotes both work the same, so pick one and keep it consistent. For building text out of pieces, use a template literal: backticks with ${...} slots that get filled in with your values. That is the tool you will reach for most.
JunoMaking strings Single and double quotes make identical strings, so choose based on which quote you need to include without escaping. Default to template literals though: backticks let you drop any value in with ${...} and span multiple lines for free. Once you interpolate, gluing strings together by hand stops feeling worth it.
JunoMaking strings Quotes are interchangeable; the only thing that picks one over the other is which character you would have to escape. Reach for backticks by default because ${...} takes a whole expression, not only a name, so arithmetic and comparisons work right inside the text. Keep plain quotes for the fixed single-piece strings where interpolation earns nothing.

Joining and measuring

You can join two strings with the + operator. This is called concatenation:

js
const firstName = "Kwame";
const greeting = "Hi " + firstName;
console.log(greeting); // Hi Kwame

Notice the space inside 'Hi '. Concatenation glues strings exactly as written, so if you forget the space you get HiKwame. A template literal usually reads better for the same job: `Hi ${firstName}`.

Every string knows its own length. Ask for it with .length:

js
const firstName = "Kwame";
console.log(firstName.length); // 5

You can also read a single character by its position, counting from zero, using square brackets:

js
const firstName = "Kwame";
console.log(firstName[0]); // K

The first character is at position 0, not 1. That zero-based counting is everywhere in JavaScript, so it is worth getting comfortable with now.

Two strings join with +, an operation called concatenation. It works, but it gets noisy fast, because every literal space and separator has to be typed inside the quotes:

js
const firstName = "Kwame";
const lastName = "Mensah";
console.log("Hi " + firstName + " " + lastName); // Hi Kwame Mensah

The same line as a template literal is `Hi ${firstName} ${lastName}`, which is why interpolation is the default for anything with more than one piece.

A string reports its size with .length, a count of its characters:

js
const firstName = "Kwame";
console.log(firstName.length); // 5

And you read a single character by index with square brackets, counting from zero, so firstName[0] is the first character and firstName[4] is the last of a five-character string:

js
const firstName = "Kwame";
console.log(firstName[0]); // K

Indexing is zero-based: the first character is at position 0.

Strings join with +, an operation called concatenation. It is fine for a quick two-part join, but note that + is overloaded: with a string on either side it concatenates, and mixing in a number coerces that number to a string, so 'total: ' + 3 gives 'total: 3' while 3 + 3 gives 6. Template literals sidestep the ambiguity by always producing text, which is one more reason to prefer them past the simplest case.

.length is a property, not a method, so you read it without parentheses:

js
const label = "Mensah";
console.log(label.length); // 6

Indexing with square brackets is zero-based and returns a one-character string:

js
const label = "Mensah";
console.log(label[0]); // M

One thing to keep in mind: .length counts the string's underlying units, not always what a human would call characters. For ordinary text the two match. For some emoji and combined characters they do not, because a single visible symbol can be stored as more than one unit, so '😀'.length reports 2. It rarely bites you, but when a count of "letters" looks off for text with emoji, that mismatch is why.

JunoJoining and measuring Join strings with +, but remember to include your own spaces, or Hi and a name run together. A template literal is usually cleaner for the same thing. Use .length to count characters, and square brackets like name[0] to read one by position, counting from zero.
JunoJoining and measuring+ concatenates, but it gets noisy the moment you have more than two pieces, so template literals win for anything real. .length counts characters and takes no parentheses because it is a property. Indexing with name[0] is zero-based, so the first character sits at position 0 and the last at length minus one.
JunoJoining and measuring+ is overloaded: string plus anything concatenates and coerces, which is a quiet source of surprises, so lean on template literals. .length is a property, no parentheses. It counts storage units, not always visible characters, so an emoji can report a length of 2. That gap only shows up with unicode, but it is worth knowing before it confuses you.

Useful string methods

Strings come with built-in methods: actions you run on a string by writing a dot and the method name. Here are the ones you will use most.

Change the case with toUpperCase() and toLowerCase():

js
const firstName = "priya";
console.log(firstName.toUpperCase()); // PRIYA

Check whether one piece of text appears inside another with includes(), which answers with true or false:

js
const message = "Welcome back";
console.log(message.includes("back")); // true

Cut out part of a string with slice(), giving it the start position and where to stop. Clean up stray spaces at the ends with trim(). And swap one piece of text for another with replace():

js
const raw = "  Hello  ";
console.log(raw.trim()); // Hello

const message = "Hi Sam";
console.log(message.replace("Sam", "Yuki")); // Hi Yuki

There are many more string methods, and you do not need them memorised. Learn these five, and look the rest up when a job calls for them.

Strings carry methods, functions you call on a string with a dot, and a handful cover most day-to-day work.

toUpperCase() and toLowerCase() change case, which is handy for comparing text the user typed without worrying about capitalisation. includes() returns a boolean for whether one string appears inside another:

js
const email = "[email protected]";
console.log(email.toLowerCase().includes("@site.com")); // true

slice(start, end) pulls out a section, from the start index up to but not including the end index. trim() removes whitespace from both ends, which you want on almost any user input. replace() swaps the first match of a piece of text for another:

js
const raw = "  order-2024  ";
const clean = raw.trim(); // 'order-2024'
console.log(clean.slice(0, 5)); // order
console.log(clean.replace("order", "invoice")); // invoice-2024

These five are the workhorses. Many more exist, so reach for the reference when you hit something they do not cover, but expect to lean on these.

Strings expose a large set of methods, functions you invoke on the value with a dot. A small core carries most of the load: toUpperCase() / toLowerCase() for case, includes() for a boolean substring check, slice(start, end) for extracting a section (start inclusive, end exclusive, and negatives count from the end), trim() for stripping surrounding whitespace, and replace() for substitution.

The property that ties them together: string methods never change the original, they return a new string. Strings are immutable, meaning a string value cannot be altered in place, so every method hands you a fresh string and leaves the source untouched:

js
const raw = "  Priya Mensah  ";
const cleaned = raw.trim().toLowerCase();
console.log(cleaned); // priya mensah
console.log(raw); // '  Priya Mensah  '  (unchanged)

Because the result is itself a string, methods chain, as trim().toLowerCase() shows above. Two edge cases worth carrying: replace() swaps only the first match unless you ask for all of them, and indexing past the end returns undefined rather than an error, so raw[999] is undefined, not a crash. That silent undefined is the kind of thing that surfaces later as a confusing result rather than a clear failure.

JunoUseful string methods Methods are actions you run on a string with a dot: toUpperCase(), includes() for a yes or no check, slice() to cut out a part, trim() to remove stray spaces, and replace() to swap text. There are plenty more, so learn these five and look up the rest when you need them.
JunoUseful string methods Lean on five: toUpperCase() and toLowerCase() for case, includes() for a boolean check, slice(start, end) to extract (end is not included), trim() for user input, and replace() for the first match. Many more exist, so reach for the reference when these fall short, but these cover most days.
JunoUseful string methods The core five are toUpperCase/toLowerCase, includes, slice, trim, and replace, and they all return a new string because strings are immutable, so results chain and the original never changes. Two traps: replace hits only the first match by default, and indexing past the end gives undefined instead of erroring, which tends to surface as a puzzling result later rather than a clean crash.

Where strings go next

Strings are one of JavaScript's core building blocks, and you now have the pieces that matter: making them with quotes or template literals, joining and measuring them, and reshaping them with methods that always return something new. The same dot-and-method pattern you used here shows up again on other types, most notably when you start working with lists in array methods.

Text also rarely travels alone. The moment you show a count, a price, or a total, you are mixing strings with numbers, and template literals are how you stitch the two together cleanly.