Stop Using substr(): Why It Breaks, What To Use Instead
Short answer: avoid substr()
. It is deprecated in the standard and may be removed in the future. Prefer slice()
in almost all cases (use substring()
only when its specific behavior is required).
Details and a migration checklist below.
Why was substr()
deprecated?
String
exposes three ways to cut text:
slice(start, end)
substring(start, end)
substr(start, length)
The first two follow the “start–end” convention. Only substr()
takes a length, which makes the mental model inconsistent and increases bugs during quick editing and code reviews. Standards bodies and browser vendors discourage it and have marked it as deprecated.
The pragmatic default: slice()
slice()
is predictable and supports negative indices.
const str = "Hello, Rex Coding!";
// Grab the last 4 characters
str.slice(-4); // "ing!"
// From index 3 to the second-last character
str.slice(3, -1); // "lo, Rex Coding"
In practice, negative indices keep code short and readable while avoiding length arithmetic.
substring()
: helpful, but sometimes too clever
Two notable behaviors:
- Negative indices are treated as 0
- If start > end, arguments are swapped internally
That can hide mistakes. Use it only when you explicitly want this behavior.
Migration checklist: substr()
-> slice()
/substring()
- Take the last N characters by length
// before
str.substr(str.length - N, N)
// after
str.slice(-N)
- From index i, take length N
// before
str.substr(i, N)
// after (equivalent)
str.slice(i, i + N)
- Only a start index (to the end)
// before
str.substr(i)
// after
str.slice(i)
- If you must ensure the smaller value is the start (like
substring
)
const start = Math.min(a, b)
const end = Math.max(a, b)
str.slice(start, end)
Conclusion
Drop substr()
. Standardize on slice()
for clarity and future safety. Reserve substring()
for rare cases where its auto-swap behavior is desired.
FAQ
- Is
substr()
gone yet? It is deprecated by standards bodies; most browsers still ship it for now, but removal can happen at any time or in constrained environments. - Do I need to replace everything today? Replace incrementally during refactors or feature work. All new code should use
slice()
. slice()
vssubstring()
? Preferslice()
(predictable, supports negatives). Usesubstring()
only when its argument-swap behavior is explicitly desired.