This article was last updated on December 31, 2024, to include common mistakes to avoid when working with JavaScript’s substring() method, such as skipping the endIndex or misunderstanding negative indices. A Frequently Asked Questions section has also been added to clarify common issues and provide practical examples.
Introduction
This post is about how to effectively use the String.prototype.substring()
method in JavaScript. We go through a few examples to understand how it works, play around to observe a few patterns and explore the quirks.
What is JavaScript substring()
?
JavaScript substring()
is a String
method that is typically used to extract and store part of a string. During the extraction, the original string remains intact, and the target part is returned as a new string.
String.prototype.substring()
is handy for producing substrings of characters from a point to another of a parent string. The substring may be from the beginning, in-between specified indexes or from the tail.
In this post, we perform some exercise with the JS substring()
method by going through a few examples. We start by getting familiar with the method signature of String.prototype.substring()
, the required argument (startIndex
), the additional argument (endIndex
) and understand which ones to use when. We then go ahead and see examples of extracting a number of characters after a starting index, characters from a range between two indexes, characters from the beginning and from the tail. While doing so, we elaborate on a few patterns of extraction from a parent string: namely, that of extracting a tail after first n
characters, another of producing a substring composed of first n
characters and that of extracting last n
characters.
In the later half of the post, we discuss some of the nuances associated with startIndex
and endIndex
values. In the end, we point out how JavaScript String.prototype.substring()
compares to String.prototype.slice()
as well as the deprecated method String.prototype.substr()
.
Step by step, we'll cover the following topics:
- Introduction
- JavaScript
substring()
MethodArray.prototype.substring()
Method Signature- JavaScript
substring()
withstartIndex
Only - Extract Tail After First
n
Characters - JavaScriptsubstring()
- JavaScript
String.prototype.substring()
- Extract a Substring Between Two Points - Extract First
n
Characters - JavaScriptsubstring()
- Extract Last
n
Characters UsingString.prototype.substring()
- Nuances of
startIndex
andendIndex
in JavaScriptsubstring()
String.prototype.substring()
Comparison- Common Mistakes When Working With substring()
- Frequently Asked Questions
- Summary
JavaScript substring()
Method
Array.prototype.substring()
takes two possible arguments: a startIndex
and an endIndex
. startIndex
is mandatory, while endIndex
can be passed to explicitly indicate the termination of extraction.
Array.prototype.substring()
Method Signature
We can call substring()
with the below possible signatures:
substring(startIndex);
substring(startIndex, endIndex);
startIndex
represents the point where substring extraction kicks off. The value at startIndex
is inclusive, i.e. it is included in the returned substring. The endIndex
denotes termination of the extraction. However, the value at endIndex
is excluded. This means that we end extraction at the character before endIndex
.
Let's see this in action with some examples.
JavaScript substring()
with startIndex
Only
With only startIndex
passed to substring()
, we get a substring that begins at startIndex
and spans to the end of the parent string:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
console.log(mnemonic.substring(14)); // "cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked."
As we can figure out from the string above, chopping starts at startIndex
and we get the tail from that point on.
Extract Tail After First n
Characters - JavaScript substring()
Since we are using a zero-based index for startIndex
, the first startIndex
number of characters are represented by the index just before startIndex
. And since the value at startIndex
is included in the extracted tail, the following pattern emerges where with startIndex = n
, we get the tail after first n
characters in the parent string:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
// Extract characters after first 14
console.log(mnemonic.substring(14)); // "cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked."
// Extract tail after first 20
console.log(mnemonic.substring(20)); // "monkeys, and, zebras, in, large, cages, make, sure, padlocked."
// Extract tails after 29
console.log(mnemonic.substring(29)); // "and, zebras, in, large, cages, make, sure, padlocked."
// Extract after 72
console.log(mnemonic.substring(72)); // "padlocked."
JavaScript String.prototype.substring()
- Extract a Substring Between Two Points
When we pass both the startIndex
and endIndex
, we get a substring of characters in startIndex <= str < endIndex
range:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
console.log(mnemonic.substring(14, 27)); // "cats, monkeys"
This means, now we end up with a substring that ends before the endIndex
.
Extract First n
Characters - JavaScript substring()
When we need a substring from the start of the parent string, the startIndex
should be 0
:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
console.log(mnemonic.substring(0, 27)); // "Please send, cats, monkeys"
With startIndex = 0
and endIndex = n
, we get the first n
characters from the parent string:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
// First 12 characters
console.log(mnemonic.substring(0, 12)); // "Please, send"
// First 18 characters
console.log(mnemonic.substring(0, 18)); // "Please, send, cats"
// First 27 characters
console.log(mnemonic.substring(0, 27)); // "Please, send, cats, monkeys"
// First 70 characters
console.log(mnemonic.substring(0, 70)); // "Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure"
Extract Last n
Characters Using String.prototype.substring()
We can get the last n
characters by leveraging the caller length
in startIndex
:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
// Last 9 characters
console.log(mnemonic.substring(mnemonic.length - 9)); // "padlocked."
// Last 15 characters
console.log(mnemonic.substring(mnemonic.length - 15)); // "sure, padlocked."
The way the above pattern works is that mnemonic.length
sets the startIndex
just outside the parent string. Moving startIndex
back by -n
repositions the extraction entry to the tail by n
. And since we are not passing endIndex
, extraction continues till the end of the string. So, we get the last n
characters.
Nuances of startIndex
and endIndex
in JavaScript substring()
Other quirks of using substring()
include cases when startIndex
is greater than endIndex
and when either of startIndex
and endIndex
or both are negative. Let's look at them one by one.
JavaScript substring()
with startIndex > endIndex
When startIndex
is greater than endIndex
JavaScript substring()
swaps the indexes to produce the substring:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
// Swaps to mnemonic.substring(0, 6)
console.log(mnemonic.substring(6, 0)); // "Please"
JavaScripty substring()
with Negative startIndex
and endIndex
A negative value of startIndex
or endIndex
sets the respective value to 0
:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
// Same as mnemonic.substring(0, 6)
console.log(mnemonic.substring(-1, 6)); // "Please"
// Same as mnemonic.substring(0, 0)
console.log(mnemonic.substring(-1, -6)); // ""
// // Same as mnemonic.substring(12, 0)
console.log(mnemonic.substring(12, -6)); // "Please, send"
In the last invocation above, swapping between startIndex
and endIndex
is also involved since 12 > 0
. The call is equivalent to mnemonic.substring(0, 12);
.
String.prototype.substring()
Comparison
In this section, we briefly discuss how JavaScript substring()
method differs from slice()
and substr()
, which are also similar String
extraction methods.
JavaScript substring()
vs slice()
String.prototype.substring()
and String.prototype.slice()
both implement string extraction almost identically. However, there are some subtle differences in their implementations.
For example, swapping of arguments -- which we saw above in substring()
-- doesn't take place in slice()
when startIndex > endIndex
:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
// Swaps to mnemonic.substring(0, 6)
console.log(mnemonic.substring(6, 0)); // "Please"
// Doesn't swap. Returns empty string, meaning non-existent characters
console.log(mnemonic.slice(6, 0)); // ""
With slice()
, startIndex > endIndex
returns an empty string.
Another difference is when either or both of startIndex
and endIndex
are negative. In general, when they are negative, slice()
wraps startIndex
and endIndex
to the tail by traversing backward from the last character. And then if startIndex < endIndex
, slicing works:
const mnemonic = "Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
// Zeroes and swaps to mnemonic.substring(0, 18)
console.log(mnemonic.substring(18, -12)); // "Please, send, cats"
// Doesn't swap, -12 finds index from tail. String is long enough, slicing works
console.log(mnemonic.slice(20, -12)); // "monkeys, and, zebras, in, large, cages, make, sure"
.........
console.log(mnemonic.substring(-12, 18)); // "Please, send, cats"
// Doesn't swap. -12 finds index from tail, but startIndex > endIndex. Returns non-existent string
console.log(mnemonic.slice(-12, 18)); // ""
.........
console.log(mnemonic.substring(-16, -12)); // ""
// Both startIndex and endIndex finds index from tail. startIndex < endIndex. Slicing works
console.log(mnemonic.slice(-16, -12)); // "sure"
JavaScript substring()
vs substr()
JavaScript substr()
is also another method for extracting substrings from a parent string. However, it is a legacy String
method that accepts the length
of the target substring, instead of an index for extraction exit.
In other words, with substr()
, we get indicate the length
of the substring:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
console.log(mnemonic.substring(10, 12)); // "nd"
// Gets 12 characters starting from startIndex onwards
console.log(mnemonic.substr(10, 12)); // "nd, cats, mo"
Also, as with slice()
, with a negative startIndex
, substr()
counts backwards from the last character:
const mnemonic =
"Please, send, cats, monkeys, and, zebras, in, large, cages, make, sure, padlocked.";
console.log(mnemonic.substring(-10, 12)); // "Please, send"
// startIndex wraps to 10 items from tail. Gets 10 characters from tail, doesn't have the other 2
console.log(mnemonic.substr(-10, 12)); // "padlocked."
In this case, only 10
characters are picked because 2
out of targeted 12
are not available in the last 10
characters.
Common Mistakes When Working With substring()
Over the years, I have encountered a few mistakes developers make using the substring() method. Let me outline them below.
Skipping endIndex
A lot of us forget that the endIndex is optional. If you don’t pass it, substring() just extracts everything from the startIndex to the end of the string. That’s OK most of the time, but if you accidentally leave it out when you meant to extract a certain range, it may mess things up.
const text = "Hello, World!";
console.log(text.substring(7)); // "World!"
console.log(text.substring(7, 12)); // "World"
Before using substring(), I double-check whether I really need the endIndex or not.
const text = "Hello, World!";
console.log(text.substring(-5)); // "Hello, World!" (negative becomes 0)
console.log(text.slice(-5)); // "orld!"
What I do now: In cases when I need negative indexing, I stick with slice().
Reversed Indices Confusion
If the value of startIndex is greater than the value of endIndex, substring() will swap them. If you’re not paying attention, it can lead to unexpected behavior.
const text = "Hello, World!";
console.log(text.substring(12, 7)); // "World" (indices are swapped)
console.log(text.slice(12, 7)); // "" (slice doesn't swap, just returns an empty string)
What I do now: Always ensure that startIndex <= endIndex whenever using substring().
Frequently Asked Questions
What if startIndex equals endIndex?
You will get an empty string because substring() does not include the endIndex.
const text = "Hello, World!";
console.log(text.substring(5, 5)); // ""
Can substring() change the original string?
Nope - it’s non-destructive, simply returning the new string and leaving the original alone.
const text = "Hello, World!";
const result = text.substring(7);
console.log(result); // "World!"
console.log(text); // "Hello, World!"
What if the indices are out of range?
If the indices exceed the length of the string, substring() will simply stop at the string’s end.
const text = "Hello";
console.log(text.substring(2, 10)); // "llo"
console.log(text.substring(10, 20)); // ""
How does substring() differ from slice()?
Both do similar things, but here’s the difference:
- substring() swaps indices if startIndex > endIndex. slice() doesn’t.
- slice() supports negative indices; substring() doesn’t.
const text = "Hello, World!";
console.log(text.substring(7, 12)); // "World"
console.log(text.slice(-5)); // "orld!"
Negative Indices Misconception
Here’s a big one: substring() doesn’t handle negative numbers. If you pass in a negative startIndex or endIndex, it will just treat them as 0. I’ve seen people confuse this with slice(), which actually supports negative indices.
Summary
In this post, we exercised the use of JavaScript substring()
with some basic examples. We first learned that substring()
is a String
extraction method that returns a target portion from a parent string. We got familiar with the required startIndex
argument whose value is included in the extracted substring, and also with the endIndex
argument which indicates termination of the string.
We then explored with examples how to use substring()
with only startIndex
and discovered how to extract the tail after first n
characters of the parent string. We also saw how to extract a substring between two points with startIndex
and endIndex
passed. We found out another pattern where we can produce the first n
characters by passing 0
as startIndex
and n
as the endIndex
. We also figured out how we can extract the last n
characters using caller length - n
.
Towards the later half, we touch based on some other nuances of using startIndex
and endIndex
values. In the end, we compared and discussed how substring()
differs in implementation from JavaScript slice()
and substr()
.