slice()

ES3+

Extracts a section of a string between two indices and returns it as a brand-new string, leaving the original untouched. Negative indices count backwards from the end of the string, which makes it easy to grab suffixes such as file extensions. It is the most flexible and predictable of the substring-extraction methods.

Syntax

string.slice(beginIndex, endIndex)

Parameters

beginIndex number

The index at which to begin extraction

endIndex number optional

The index before which to end extraction

Return Value

string

A new string containing the extracted section

Examples

JavaScript
const str = 'Hello World';
console.log(str.slice(0, 5));
console.log(str.slice(-5));
Output:
// 'Hello' 'World'

📌 When to Use

Use slice() whenever you need part of a string identified by position rather than by pattern: taking the first N characters for a preview, cutting off a known prefix after checking it with startsWith(), grabbing the last few characters for an extension or checksum, or extracting the text between two indices you found with indexOf(). Its support for negative indices is the killer feature: str.slice(-4) reads the last four characters without you ever touching str.length, and str.slice(0, -1) drops the final character. Compared with its siblings, slice() should be your default. substring() silently swaps its arguments when start is greater than end and treats negative numbers as zero, which hides bugs, and substr() is deprecated. Combine slice() with indexOf() or lastIndexOf() for lightweight parsing when a full regular expression would be overkill, for example splitting an email address at the @ sign or pulling the path out of a URL. Avoid slice() when the boundaries are defined by a pattern rather than a position; match() or split() express that intent more directly. Also remember indices are UTF-16 code units, so for emoji-heavy user text, position-based cutting needs extra care.

⚠️ Common Mistakes

Confusing string slice() with array splice(): splice() mutates an array in place, while slice() always returns a new string and cannot change the original, because strings in JavaScript are immutable. Writing str.slice(1) and expecting str itself to change is a classic beginner error.

Treating the end index as inclusive: slice(0, 5) returns the characters at positions 0 through 4. The character at the end index is never included, so the length of the result is end minus start, a convention shared with Array.prototype.slice and TypedArray methods.

Misreading negative indices: slice(-3) means 'the last three characters', because a negative index is added to the string length. It does not throw and it does not count from some position called minus three; likewise slice(1, -1) trims exactly one character from each end.

Cutting through a surrogate pair: indices measure UTF-16 code units, and characters outside the Basic Multilingual Plane, including virtually all emoji, occupy two units. Slicing at the wrong offset leaves a lone surrogate that renders as a replacement-character glyph. Truncate user-generated text with Intl.Segmenter or Array.from when correctness matters.

Expecting an error for out-of-range arguments: slice() never throws for bad indices. If start ends up at or beyond end after normalization, you silently get an empty string, which can hide an off-by-one bug until much later in the program.

✅ Best Practices

Make slice() your default extraction method over substring() and the deprecated substr(); its handling of negative indices is predictable and it never reorders your arguments behind your back.

Use negative indices instead of arithmetic on length: str.slice(-ext.length) is clearer and less error-prone than str.slice(str.length - ext.length).

Pair slice() with indexOf() for simple delimiter-based parsing, but always handle the -1 case from indexOf() first, because slicing from -1 + 1 = 0 or from a stale index produces plausible-looking wrong answers.

When truncating text for display, account for the ellipsis in your length budget, as in text.slice(0, max - 3) plus three dots, and consider trimming trailing whitespace so you never render a dangling space before the dots.

For text that may contain emoji or non-Latin scripts, slice by grapheme boundaries using Intl.Segmenter rather than raw code-unit indices, so a truncated username never turns into a corrupted glyph.

⚡ Performance Notes

slice() runs in time proportional to the length of the extracted section, and modern engines make it cheaper than that in practice: V8 often represents the result as a SlicedString, a lightweight view that points into the parent string instead of copying the characters. That makes even large slices effectively constant-time. The flip side is memory retention: a tiny slice can keep an enormous parent string alive in the heap, because the view holds a reference to it. If you slice a small identifier out of a multi-megabyte document and store it long-term, the whole document may be unable to be garbage collected. Forcing a real copy, for example with JSON.parse(JSON.stringify(s)) or string concatenation tricks, is an engine-specific workaround; usually the better fix is simply not to keep slices of huge transient buffers. For typical application strings, none of this matters and slice() is essentially free.

🌍 Real World Example

File Path and Extension Handling

Three compact utilities that lean on slice(). getFileExtension() finds the last dot with lastIndexOf() and slices from there, correctly returning '.gz' for 'archive.tar.gz' and an empty string when there is no dot. truncate() shortens long text to a display budget and appends an ellipsis, reserving three characters so the final string never exceeds the limit. getDomain() strips the protocol by slicing just past the double slash, then cuts again at the first following slash to isolate the host name. Each function pairs an index search with a slice, the everyday idiom for lightweight string parsing without regular expressions.

// Extract file extension
function getFileExtension(filename) {
  const lastDot = filename.lastIndexOf('.');
  return lastDot === -1 ? '' : filename.slice(lastDot);
}

console.log(getFileExtension('document.pdf')); // '.pdf'
console.log(getFileExtension('archive.tar.gz')); // '.gz'

// Truncate text with ellipsis
function truncate(text, maxLength) {
  if (text.length <= maxLength) return text;
  return text.slice(0, maxLength - 3) + '...';
}

console.log(truncate('Hello World', 8)); // 'Hello...'

// Extract domain from URL
function getDomain(url) {
  const withoutProtocol = url.slice(url.indexOf('//') + 2);
  const domainEnd = withoutProtocol.indexOf('/');
  return domainEnd === -1 ? withoutProtocol : withoutProtocol.slice(0, domainEnd);
}

console.log(getDomain('https://www.example.com/path'));
// Output: 'www.example.com'

Related Methods