jsguides

String.prototype.endsWith()

endsWith(searchString, endPosition)

The endsWith() method determines whether a string ends with the characters of a specified string, returning true or false as appropriate. It’s the counterpart to startsWith() and provides a cleaner alternative to checking the last N characters of a string.

Syntax

str.endsWith(searchString)
str.endsWith(searchString, endPosition)

Parameters

ParameterTypeDefaultDescription
searchStringstringThe characters to search for at the end of the string.
endPositionnumberstr.lengthThe end position within the string to search. If omitted, defaults to the string’s length.

Examples

Basic usage

Call endsWith() with a search string to check the end of a string. A second argument sets the effective length the method considers, which is useful when you only want to check a prefix of a longer input.

const str = 'Hello, world!';

console.log(str.endsWith('world!'));
// true

console.log(str.endsWith('Hello'));
// false

console.log(str.endsWith('world!', 13));
// true

Case-sensitive matching

The comparison is case-sensitive by design. This matters most when checking file extensions or protocol identifiers, where casing can vary depending on how the user or system produced the filename.

const filename = 'document.pdf';

console.log(filename.endsWith('.pdf'));
// true

console.log(filename.endsWith('.PDF'));
// false (case-sensitive)

console.log(filename.endsWith('document'));
// false

Using with file extensions

Filtering a list of filenames by extension is one of the most common real-world uses of endsWith(). You can chain the method with array helpers like filter() to narrow a directory listing down to a specific format.

const files = [
  'image.png',
  'photo.jpg',
  'document.pdf',
  'archive.zip'
];

const images = files.filter(file => file.endsWith('.png') || file.endsWith('.jpg'));
console.log(images);
// ['image.png', 'photo.jpg']

Common Patterns

Validating file types

Combine endsWith() with some() to test a filename against a set of allowed extensions in one pass. Normalizing to lowercase before the check avoids false negatives when the user’s file system or upload tool capitalizes the extension.

function isImage(filename) {
  const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
  return imageExtensions.some(ext => filename.toLowerCase().endsWith(ext));
}

console.log(isImage('photo.PNG'));
// true

console.log(isImage('document.pdf'));
// false

Checking URL endings

endsWith() can also inspect protocol schemes or trailing characters in URLs, but it only checks the literal end of the string. For structured URL parsing, the URL constructor is a better tool; endsWith() works best for quick suffix checks.

function isSecureUrl(url) {
  return url.endsWith('https');
}

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

console.log(isSecureUrl('http://example.com'));
// false

Use Cases

URL validation

When building web applications, you often need to validate that URLs end with certain patterns. The endsWith() method makes this straightforward. A trailing-slash check is one of the simplest examples — it tells you whether a path ends in /, which matters for routing and canonical URL resolution:

function hasTrailingSlash(url) {
  return url.endsWith('/');
}

console.log(hasTrailingSlash('https://example.com/page/'));
// true

console.log(hasTrailingSlash('https://example.com/page'));
// false

Extension checking in upload forms

In file upload scenarios, validating the file extension on the client side provides immediate feedback. Comparing against a list of allowed extensions with some() keeps the logic compact. Normalize both the filename and the allowed extensions to the same case so users are not punished for capitalization:

function validateUpload(filename, allowedExtensions) {
  return allowedExtensions.some(ext => 
    filename.toLowerCase().endsWith(ext.toLowerCase())
  );
}

const documentExtensions = ['.pdf', '.doc', '.docx'];
console.log(validateUpload('resume.PDF', documentExtensions));
// true

Comparing string endings

Unlike manual comparisons using slice() or substr(), endsWith() is semantic and readable. The slice() approach requires you to calculate the offset by hand, which is easy to get wrong when the search string length changes. endsWith() removes that arithmetic entirely:

const message = 'Hello, JavaScript developer!';

// Using endsWith() - clear intent
console.log(message.endsWith('developer!'));
// true

// Manual approach - harder to read
console.log(message.slice(-10) === 'developer!');
// true (but less clear)

Performance Considerations

The endsWith() method is optimized in modern JavaScript engines. For older environments, a polyfill is available. The method handles Unicode correctly and doesn’t suffer from the edge cases that plague manual length calculations.

Edge Cases

A few edge cases are worth knowing. An empty search string always returns true, a position beyond the string length is clamped to the actual length, and casing is always honored.

// Empty search string always returns true
console.log('hello'.endsWith(''));
// true

// Position beyond string length uses string length
console.log('hi'.endsWith('hi', 100));
// true

// Case matters
console.log('HELLO'.endsWith('hello'));
// false

endsWith() vs slice() and indexOf()

Before endsWith() was available in ES6, the same check required either slice() or lastIndexOf(). Both workarounds are fragile — slice() demands an exact negative offset, and indexOf() needs a manual length calculation that is easy to mistype:

const str = "hello world";

// ES6 — semantic and readable
str.endsWith("world");

// Pre-ES6 with slice — fragile, must get length right
str.slice(-5) === "world";

// Pre-ES6 with indexOf — wordy
str.indexOf("world") === str.length - "world".length;

endsWith() is the right tool because the intent is explicit and there are no manual length calculations to get wrong.

endsWith() vs regex

Regular expressions can match the end of a string with the $ anchor. endsWith() is faster and more readable for literal suffix checks because there is no regex compilation overhead and the intent is immediately visible:

// Both check for ".json" at the end
"data.json".endsWith(".json");        // true
/\.json$/.test("data.json");          // true

// endsWith wins for fixed suffix checks — no regex compilation
// Regex is better when the suffix pattern itself is dynamic or complex
const ext = getUserInput();
filename.endsWith(ext);               // fine for fixed string

For checking multiple extensions at once, endsWith() in a .some() call reads more clearly than a single complex regex:

const imageExts = [".jpg", ".png", ".webp", ".gif"];
const isImage = imageExts.some(ext => filename.endsWith(ext));

The endPosition parameter

When you pass a second argument to endsWith(), it treats the string as if it ends at that position. This is useful for checking a prefix within a larger string, or for validating a specific segment. The parameter narrows the view window without slicing the string first:

const version = "v2.3.1-beta";
version.endsWith("2.3.1", 7); // true — checks first 7 chars: "v2.3.1"

If endPosition is greater than the string’s length, it defaults to str.length. If it is 0 or negative, the method returns false.

When endsWith() is the better fit

endsWith() is the better fit whenever the question is “does this string end with this exact text?” That directness is why it reads better than slicing, and it is usually safer than a regular expression for fixed suffix checks. You can look at the call and immediately see that you are comparing the end of the string, not searching somewhere in the middle.

It also pairs well with validation logic for filenames, URLs, and tokens where the suffix matters more than the rest of the string. In those cases, endsWith() keeps the code compact and makes the rule easier to revise later, especially when the allowed endings are stored in a list and checked with some().

See Also