There's no need for the 2nd argument in substr
. So you could just do:
origin.substr(target.length * -1) === target
or
origin.slice(target.length * -1) === target
Same deal.
Edit: Whoops. Actually it's not quite the same deal. As Sumurai8 commented on Simon's answer, MDN says that JScript does not handle negative offsets for substr
. However, slice
has no such caveat. So long story short: Use slice
, not substr
.
Instead of * -1
, you could also use a unary minus:
origin.slice(-target.length) === target
One thing you might want, though, is to check target
before you try accessing its length
property. If target == undefined
you'll get an error. Something simple like this should do:
if(!target) return false;
One gotcha though: It'll return false if target
is an empty string, since empty strings are false'y. However, it doesn't really make much sense to check if string ends with an empty string, so perhaps that's fine? Otherwise, do a typeof
check (like the one below) on target
.
And you might want to check origin
too. However, here you just want to check that it's a string - not if it's just false'y. You'll be calling slice
on it, so it must be a string or you'll get an error, whereas the worst that can happen if target
isn't a string (but is truth'y) is that target.length
is undefined
.
So to check origin
do:
if(typeof origin !== 'string') return false;
By the way, without the target
-is-false'y check, if target
is a string but also empty, you'll get some tricky results:
Origin Target Result
==========================================
"foo" "" false
"" "foo" false
"" "" true
Results #2 makes sense, but results #1 and #3 are perhaps a little strange, because, again, what does it mean to have an string end with an empty string? The results are due to slice(-0)
being the same as slice(0)
, i.e. returning the whole string. So in effect you're checking:
"foo".slice(0) == "" // => "foo" == "" (false)
"".slice(0) == "" // => "" == "" (true)
Kinda confusing.
If you want an empty target string to always return true, you could do:
if(typeof origin !== 'string') return false;
if(typeof target !== 'string') return false;
if(!target) return true;
I'm aware my code has a lot of white-space for JavaScript standards. I like to think it keeps code readable. The naming can probably be improved.
Whitespace seems just fine to me! Don't know what JS you're used to, but I see absolutely no reason to change anything about whitespace usage.
I would drop the outer parentheses though, like Simon suggested.
As for naming, I'd call it endsWith
, or stringEndsWith
.
You could also extend the String
prototype with an endsWith
method, but generally it's better to leave native prototypes alone. However, this is fairly harmless, so I'd be tempted to say:
if(!String.prototype.endsWith) {
String.prototype.endsWith = function (ending) {
if(typeof ending !== 'string') return false;
if(!ending) return true;
return this.slice(-ending.length) === ending;
};
}
Here we can skip checking origin
, because we're adding the method to String
itself. So if it's called, it's called on a string.
String
prototype. \$\endgroup\$endsWith
instead.isEndOf
seems particularly unfortunate with that parameter order, because to me, the code reads as "IsA long time ago in a galaxy far, far away
the end offar away
?" \$\endgroup\$String
are global - this is not the case in C#, where you can include/exclude a specific namespace. \$\endgroup\$