JavaScript Strings — The Basics
Build a real mental model of JavaScript strings: why they're immutable, how indexing and length work, template literals, and how searching, slicing and transforming all return new strings.
Introduction
A string is a sequence of characters — text held in a single value. Anything you type, display, or read from a user is a string: a name, a URL, a line from a file, the contents of an input box. You write one with quotes, and JavaScript treats single quotes, double quotes and backticks as three ways to spell the same kind of value.
Why does text need its own type, distinct from numbers? Because the operations differ completely: you don't add two names, you *join* them; you don't halve a sentence, you *slice* it. A dedicated string type gives you a vocabulary — length, indexing, search, slice, replace, split — for working with text as a first-class thing rather than a bag of characters.
The one idea that makes everything else fall into place is immutability: a JavaScript string can never be changed once created. Every method that looks like it edits a string actually returns a brand-new one. Hold onto that and the rest of this guide — indexing, length, template literals, searching and slicing — is just detail hung on that frame.
const single = 'hello';
const double = "hello";
const backtick = `hello`; // a template literal — more on these below
Lessons
1. Strings are immutable
This is the foundation. A string is immutable: none of its characters can be reassigned, and no method changes it in place. toUpperCase(), replace(), slice() — every one of them leaves the original untouched and hands you a *new* string. If you want the result, you must capture the return value; calling a string method and ignoring what it returns does nothing at all.
let greeting = 'hello';
greeting.toUpperCase(); // returns 'HELLO' — but we ignored it
console.log(greeting); // 'hello' — unchanged
greeting = greeting.toUpperCase(); // capture the new string
console.log(greeting); // 'HELLO'
Because strings are immutable, you never worry about one part of your program changing a string another part is holding — a common source of bugs with mutable values like arrays. The trade-off is that you must *reassign* to keep a transformed result.
2. Length and indexing
A string knows its size through length, and you reach any character by its index, counting from 0 — exactly like an array. The last character sits at index length - 1, or more readably at at(-1). Reading past the end returns undefined rather than throwing.
const word = 'JavaScript';
word.length; // 10
word[0]; // 'J' (first character)
word.at(-1); // 't' (last character)
word[99]; // undefined — no error for a missing index
3. Building strings: concatenation and template literals
You can join strings with +, but the modern and far more readable way is a template literal — a string in backticks where ${...} drops a value straight into the text. Template literals also span multiple lines without escape characters, which makes building messages, HTML or SQL far cleaner than gluing pieces together with +.
const name = 'Ada';
const age = 36;
const plus = 'Hi ' + name + ', age ' + age; // old way
const tmpl = `Hi ${name}, age ${age}`; // template literal
console.log(tmpl); // 'Hi Ada, age 36'
4. Searching inside a string
To ask whether a string contains something, reach for includes() — it returns a plain true or false. When you need the position, indexOf() returns the index of the first match or -1 if there is none, and startsWith() / endsWith() answer the common edge cases directly. These are the everyday tools for validation and matching.
const url = 'https://xcodx.io/editor';
url.includes('xcodx'); // true
url.startsWith('https'); // true
url.indexOf('/editor'); // 15 (-1 if not present)
5. Taking a piece with slice
To copy a run of characters into a new string, use slice(start, end). Like array slicing it is half-open — it includes start and excludes end — and it accepts negative indices to count from the end. Because a string is immutable, slice() can only ever return a new string; the original is never touched.
const s = 'JavaScript';
s.slice(0, 4); // 'Java' (index 0 up to, not including, 4)
s.slice(4); // 'Script' (to the end)
s.slice(-6); // 'Script' (last six characters)
6. Transforming: case, whitespace, replace and split
The remaining everyday operations all follow the same immutable pattern — each returns a new string. toUpperCase() / toLowerCase() change case; trim() removes surrounding whitespace (invaluable for cleaning user input); replace() swaps text; and split() breaks a string into an array of pieces around a separator. Two of these are big enough to have their own reference pages.
replace()— swap the first match (or, with a global regex, every match) for new text.split()— break a string into an array, e.g. a CSV line into fields.trim(),toUpperCase(),padStart()and friends — small, single-purpose transforms you'll reach for constantly.
That's the whole model. A string is an immutable sequence of characters; length and 0-based indexing reach into it; template literals build it; includes/indexOf search it; slice copies a piece of it; and the transforming methods each hand back a *new* string. Everything else is a specific method resting on those ideas.
Practice
Check your model. Given let s = 'hello', what does s.toUpperCase() on its own line leave in s? (Answer: 'hello' — the method returns 'HELLO' but strings are immutable, so s is unchanged unless you reassign it.)
Now experiment for real — build a greeting with a template literal, then slice and upper-case a piece, and confirm the original survives every step:
Next steps
You have the mental model — now put it to work. Browse runnable JavaScript string examples for copy-paste snippets, follow how to reverse a string for a classic task, or read the focused references for replace() and split(). If arrays are next on your list, start with JavaScript arrays — the basics. Every snippet runs in the online JavaScript compiler or the full editor.
Frequently asked questions
Are JavaScript strings mutable?
How do I get the last character of a string?
str[str.length - 1], or the more readable str.at(-1). The last index is length - 1 because indexing starts at 0.What's the difference between single quotes, double quotes and backticks?
${expression} interpolation and multi-line text.How do I check whether a string contains another string?
str.includes('text') for a true/false answer, or str.indexOf('text') when you need the position (it returns -1 if not found).