String.prototype.substr()

Extracts a run of characters of a given length starting at an index (deprecated).

Signature
substr(start)
substr(start, length)
  • Added in JavaScript ES3 (Annex B)
  • Deprecated since PHP Deprecated — defined only in Annex B, normative optional outside browsers

Parameters

ParameterTypeDescription
$startoptionalnumber= 0The index of the first character to include in the returned substring. A negative value counts back from the end of the string, as max(start + str.length, 0).
$lengthoptionalnumberThe number of characters to extract. If omitted or undefined, extraction runs to the end of the string. A negative value returns an empty string.

Return value

stringA new string containing the specified part of the given string.

Changelog

  • PHP Annex Bsubstr() is not part of the main ECMAScript specification; it lives in Annex B: Additional ECMAScript Features for Web Browsers, which is normative optional for non-browser runtimes.

substr() is the odd one out among the string extractors: its second argument is a count of characters, not an end index. "abcdef".substr(1, 3) returns "bcd", whereas "abcdef".substring(1, 3) returns "bc". Mixing the two up is the single most common bug involving this method.

Why it is deprecated

It is defined in Annex B: Additional ECMAScript Features for Web Browsers rather than the main specification. Browsers must implement it for backwards compatibility, but other runtimes are only optionally required to. It is not going to be removed from browsers any time soon, yet new code should not rely on it.

What to use instead

Use slice(). It also accepts negative start indices, so the migration is usually mechanical: s.substr(start, len) becomes s.slice(start, start + len) for a non-negative start, or s.slice(start, start + len || undefined) when start is negative and the sum could reach 0. When you only pass one argument, substr(n) and slice(n) are already identical.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Read a fixed-width column out of a legacy flat file
  • Maintain older code that already uses substr throughout
  • Grab the last n characters with a negative start

Frequently asked questions

Is String.prototype.substr deprecated?

Yes. substr() is defined in Annex B of the ECMAScript specification, the section for legacy web-compatibility features, and MDN marks it deprecated. Browsers will keep supporting it, but new code should use slice() or substring() instead.

What is the difference between substr and substring?

substr()'s second argument is the number of characters to extract, while substring()'s second argument is the index to stop before. "abcdef".substr(1, 3) is "bcd" but "abcdef".substring(1, 3) is "bc".

How do I replace substr with slice?

Convert s.substr(start, length) into s.slice(start, start + length) when start is non-negative, and drop the second argument entirely when substr had only one. slice() also supports negative start indices, so s.substr(-4) becomes s.slice(-4) unchanged.

More examples

substr vs substring vs slice

The first three lines show the length-versus-index split: substr returns one more character than the other two for the same numbers. The rest shows substr's edge handling — a negative length yields an empty string rather than counting backwards.

Example · javascript
const s = "abcdef";

console.log(s.substr(1, 3));    // "bcd" — 3 characters
console.log(s.substring(1, 3)); // "bc"  — up to index 3
console.log(s.slice(1, 3));     // "bc"  — up to index 3

console.log(s.substr(1, -1));   // ""    — negative length
console.log(s.substr(20, 2));   // ""    — start past the end
console.log(s.substr(-20, 2));  // "ab"  — start clamped to 0

Migrating a fixed-width parser to slice

Both objects come out identical, which is the point: each substr(offset, width) maps to slice(offset, offset + width). The true on the last line confirms the rewrite is faithful.

Example · javascript
const record = "SMITH     JOHN      19850312";

const legacy = {
  last: record.substr(0, 10).trim(),
  first: record.substr(10, 10).trim(),
  dob: record.substr(20, 8),
};

const modern = {
  last: record.slice(0, 10).trim(),
  first: record.slice(10, 20).trim(),
  dob: record.slice(20, 28),
};

console.log(legacy);
console.log(JSON.stringify(legacy) === JSON.stringify(modern));

Discussion

  • Be the first to comment on this lesson.