endsWith()

ES6+

Determines whether a string ends with the characters of a given search string, returning true or false. An optional length argument makes the check behave as if the string were only that long, so you can test for a suffix at an interior boundary. The comparison is case-sensitive and literal, added in ES2015.

Syntax

string.endsWith(searchString, length)

Parameters

searchString string

The characters to search for at the end

length number optional

Length of string to search within

Return Value

boolean

true if the string ends with the given characters

Examples

JavaScript
const str = 'Hello World';
console.log(str.endsWith('World'));
console.log(str.endsWith('Hello'));
Output:
// true false

📌 When to Use

Use endsWith() whenever the question is anchored to the end of a string: validating file extensions before an upload, checking whether a URL or path already carries a trailing slash, detecting sentence-final punctuation, matching hostname suffixes like '.example.com', or recognizing unit suffixes such as 'px' or '%' in style values. Anchoring is the point: filename.includes('.png') is true for 'fake.png.exe', while filename.endsWith('.png') is not, which is exactly the difference between a decorative check and a meaningful one. It replaces the old arithmetic idioms, comparing lastIndexOf() against a computed offset or slicing the tail and comparing, both of which invite off-by-one errors that endsWith() simply cannot have. The optional length parameter is a niche but elegant tool: endsWith('World', 11) asks whether 'World' ends at position 11, letting you test suffixes of a logical prefix without allocating a slice. As with its siblings, the comparison is case-sensitive, so extension checks should lowercase the filename first, given that 'photo.JPG' is a perfectly normal filename. It throws a TypeError for regex arguments; suffix patterns, like 'ends with a digit', belong to an end-anchored regular expression with test(). For trust decisions on domains, prefer parsing the hostname and comparing labels, since raw suffix matching on 'example.com' also accepts 'notexample.com'.

⚠️ Common Mistakes

Checking file types case-sensitively: 'photo.JPG'.endsWith('.jpg') is false, and cameras and Windows systems produce uppercase extensions constantly. Lowercase the filename before testing, or valid uploads will be rejected intermittently.

Using includes() for extension validation: 'malware.png.exe'.includes('.png') is true. Only an anchored endsWith() ties the extension to the actual end of the name, and even that is a formatting check, not proof of file content; server-side type sniffing is still required for security.

Suffix-matching domains without a separating dot: hostname.endsWith('example.com') accepts 'notexample.com'. Test for '.example.com' or compare the exact hostname, and ideally operate on a parsed URL rather than the raw string.

Misreading the second parameter as a start position: it is a virtual length. str.endsWith('lo', 5) asks whether the first five characters end in 'lo'; passing an index where you meant a length yields silently wrong booleans.

Passing a regular expression: endsWith() throws a TypeError rather than converting it. An end-anchored regex with test() is the tool for suffix patterns like optional digits or alternate extensions.

Forgetting the empty-string edge case: endsWith('') is always true, so an extension list that accidentally contains an empty entry approves every filename.

✅ Best Practices

Lowercase once, then test many: normalize the filename a single time and check it against a lowercase extension list with some(), as in exts.some(e => lower.endsWith(e)).

Keep suffix checks anchored and honest: use endsWith() rather than includes() for extensions and trailing markers, and remember it validates the name only, never the file's actual content.

Include the delimiter in the suffix you test: '.png' rather than 'png', and '.example.com' rather than 'example.com', so lookalike values cannot slip through.

Use the verify-then-slice idiom for suffix removal: after str.endsWith(suffix) passes, str.slice(0, -suffix.length) removes exactly what was confirmed.

Reach for the length parameter instead of allocating slices when testing suffixes at interior boundaries during parsing.

For URL and domain logic, parse with the URL constructor and compare hostnames or labels; keep endsWith() for formatting concerns like trailing slashes.

⚡ Performance Notes

endsWith() compares at most suffix-length code units at a computed offset and bails at the first mismatch, so its cost is bounded by the suffix length regardless of how long the subject string is, and it allocates nothing. That makes it cheaper than the slice-the-tail-and-compare idiom, which creates a temporary string per test, and far cheaper than a regex for the same literal check once pattern compilation and matching overhead are counted. Testing a filename against a list of five extensions with some() performs at most a handful of short comparisons and is effectively free even inside large directory scans. The one hidden cost in typical usage is the case normalization: toLowerCase() on the filename allocates a new string, so hoist it out of the extension loop, doing it once per filename rather than once per extension tested.

🌍 Real World Example

File Extension and Type Validation

Three suffix-anchored utilities. isAllowedImageFile() lowercases the filename once, then tests it against a list of image extensions with some() and endsWith(), correctly accepting 'photo.JPG' while rejecting 'document.pdf'; being anchored to the end, it cannot be fooled by an extension buried mid-name. normalizeUrl() checks for a trailing slash and appends one only when missing, the standard idempotent normalization before joining paths or comparing URLs. getFileCategory() extends the same some-plus-endsWith pattern into a small classifier, mapping extension groups to image, video, audio, or document buckets, the shape of logic behind upload pickers and file-manager icons.

// Validate file extension for upload
function isAllowedImageFile(filename) {
  const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
  const lowerName = filename.toLowerCase();
  return allowedExtensions.some(ext => lowerName.endsWith(ext));
}

console.log(isAllowedImageFile('photo.JPG')); // true
console.log(isAllowedImageFile('document.pdf')); // false

// Ensure URL ends with trailing slash for consistency
function normalizeUrl(url) {
  if (!url.endsWith('/')) {
    return url + '/';
  }
  return url;
}

console.log(normalizeUrl('https://example.com'));
// 'https://example.com/'

// Get file type category from filename
function getFileCategory(filename) {
  const lower = filename.toLowerCase();

  if (['.jpg', '.jpeg', '.png', '.gif', '.webp'].some(e => lower.endsWith(e))) {
    return 'image';
  }
  if (['.mp4', '.webm', '.avi', '.mov'].some(e => lower.endsWith(e))) {
    return 'video';
  }
  if (['.mp3', '.wav', '.ogg', '.flac'].some(e => lower.endsWith(e))) {
    return 'audio';
  }
  if (['.pdf', '.doc', '.docx', '.txt'].some(e => lower.endsWith(e))) {
    return 'document';
  }
  return 'other';
}

console.log(getFileCategory('report.PDF')); // 'document'
console.log(getFileCategory('song.mp3')); // 'audio'

Related Methods