JavaScript Substring vs Substr: Differences Explained
String manipulation in JavaScript is an essential capability that every developer regularly faces. Among the functions that often confuse developers are substring()
and substr()
. Although they may appear similar at first, they behave differently, which can result in unexpected outcomes if not clearly understood. This article will highlight the fundamental differences between these methods, illustrate their practical uses, and assist you in selecting the appropriate one for your needs.
Understanding the Functions
Both substring()
and substr()
are used to extract parts of strings; however, they interpret their parameters in distinct ways. Recognising this variation is vital for sidestepping bugs in your code.
The substring()
function accepts two parameters: a starting index and an ending index. It returns the string segment from the start index up to, but not including, the end index.
string.substring(startIndex, endIndex)
Conversely, substr()
requires a start index and a length parameter. It outputs a substring beginning at the specified starting point, extending for a predetermined number of characters.
string.substr(startIndex, length)
Here's a significant point that often confounds developers: substr()
is now considered deprecated per the ECMAScript guidelines, even though it's still widely used for backward compatibility. The MDN documentation strongly advises against employing substr()
in newly written code.
Comparison of Key Features
Characteristic
substring()
substr()
Second Argument
End index (not inclusive)
Length of the substring
Handling Negative Values
Considered as 0
Start index can accept negatives (counts from the end)
Parameter Exchange
Automatically swaps when start index is greater than end
No automatic swapping
Status in Standards
Standard (ES1)
Deprecated (Legacy)
Browser Compatibility
Supported universally
Also universally supported but not recommended
Real-world Examples
Let’s review how these functions work with practical examples:
const text = "Hello, World!";
// Basic usage
console.log(text.substring(0, 5)); // "Hello"
console.log(text.substr(0, 5)); // "Hello"
// Different second parameters
console.log(text.substring(7, 12)); // "World" (positions 7 to 11)
console.log(text.substr(7, 5)); // "World" (starting at 7, taking 5 characters)
// Negative values
console.log(text.substring(-3, 5)); // "Hello" (negative treated as 0)
console.log(text.substr(-6, 5)); // "World" (starts 6 characters from the end)
// Parameter order matters
console.log(text.substring(12, 7)); // "World" (parameters swapped)
console.log(text.substr(12, 7)); // "" (empty string, characters after position 12)
Common scenarios include:
- Extracting file extensions:
filename.substring(filename.lastIndexOf('.') + 1)
- Trimming text for previews:
article.substring(0, 150) + "..."
- Parsing out URLs or subdomains
- Processing CSV data or fixed-width text formats
Performance Insights
Generally, the performance differences between the two methods are minimal for most uses. Nevertheless, substring()
usually executes with slightly better efficiency due to optimizations in modern JavaScript engines.
// Performance testing (execute in browser console)
const testString = "A".repeat(10000);
const iterations = 100000;
console.time("substring");
for (let i = 0; i < iterations; i++) {
testString.substring(100, 200);
}
console.timeEnd("substring");
console.time("substr");
for (let i = 0; i < iterations; i++) {
testString.substr(100, 100);
}
console.timeEnd("substr");
For typical use cases, both methods perform within microseconds, so performance shouldn't be a major concern.
Best Practices to Avoid Mistakes
Follow these recommendations to prevent common errors and create maintainable code:
- Opt for
substring()
in new projects - It is the standard-compliant choice
- Always validate indices - Ensure start and end parameters are within bounds
- Consider using
slice()
as an alternative - It deals with negative indices more intuitively than substring()
- Document your purpose - Comment on your code to explain why particular indices were chosen
Common issues to be vigilant about:
const text = "JavaScript";
// Issue 1: Confusion between length and end index
// Incorrect: trying to access first 4 characters
console.log(text.substring(0, 4)); // "Java" ✓
console.log(text.substr(0, 4)); // "Java" ✓
// Issue 2: Handling negative indices
console.log(text.substring(-3)); // "JavaScript" (returns all)
console.log(text.substr(-3)); // "ript" ✓
// Issue 3: Confusion with parameter order
console.log(text.substring(4, 0)); // "Java" (automatically swapped)
console.log(text.substr(4, 0)); // "" (returns empty string)
Transitioning from substr() to substring()
If you're managing legacy code that employs substr()
, here's a guide for a smooth transition:
// Original usage of substr()
const original = text.substr(startPos, length);
// Adapt to substring()
const converted = text.substring(startPos, startPos + length);
// Address negative start positions
function safeSubstring(str, start, length) {
if (start < 0) {
start = Math.max(0, str.length + start);
}
return str.substring(start, start + length);
}
// Usage example
const result = safeSubstring("Hello World", -5, 5); // "World"
Modern Methods and Alternatives
Newer JavaScript versions present additional string manipulation techniques that may better serve your requirements:
const text = "Hello, World!";
// slice() - analogous to substring but manages negatives like substr
console.log(text.slice(0, 5)); // "Hello"
console.log(text.slice(-6, -1)); // "World"
// Template literals for more complex string concatenation
const start = 7;
const end = 12;
const extracted = text.slice(start, end);
const result = Extracted: "${extracted}" from position ${start} to ${end}
;
// Regular expressions for pattern-based extraction
const emailRegex = /([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+.[a-zA-Z]{2,})/;
const email = "[email protected]";
const [, username, domain] = email.match(emailRegex) || [];
console.log(username); // "contact"
For more intricate string tasks, consider using utility libraries such as Lodash's string functions or the built-in String prototype methods.
Your choice among string manipulation functions should ultimately hinge on your specific application, but relying on standardized functions like substring()
and slice()
will make certain that your code is maintainable and future-ready. Prioritising clarity and consistency in your code is often more valuable than small performance gains.

This article integrates insights and content from multiple online sources. We acknowledge the contributions of all original creators, publishers, and websites. Though we strive to properly credit source material, any unintended missed acknowledgments do not equate to copyright violations. All trademarks, logos, and images mentioned belong to their respective owners. Should you believe any part of this article violates your copyright, please reach out to us immediately for review and necessary action.
This article is designed for educational and informational purposes, not infringing on any copyrights. If any material is used without proper credit unintentionally, we will promptly rectify it upon notification. Please note that the republishing or distribution of any parts or entirety of this content is prohibited without explicit written consent from the author and website owner. For permissions or inquiries, please get in touch with us.