I'm a Java guy in a JavaScript world, and I'm used to certain things about Java Strings that just aren't there for in JavaScript. Some of this I can accept, for example Strings are freaking everywhere for some reason.
Now I realize this could be simply implemented with return this.indexOf(needle) === 0;
(or, even more JavaScripty, return this.indexOf(needle);
but the flaw in that is that it will search the entire (potentially somewhat lengthy, you never know) String in its endeavor to find the index, when I really only care if its non-zero.
My current solution, which passes my testing so far, is thus. I'm open to all feedback, but I'm most interested in
- Breaks from conventional JavaScript (the bad stuff, the smells)
- Corner-cases this fails for
- To a reasonable extent, style
I've also decided to tack it onto the class itself (I have to admit, I like being able to do that!) Is that bad practice?
String.prototype.startsWith = function(needle) {
// This was dubious, if only because most times "" gets passed
// it's by mistake... but decided since it was technically correct
// that it should stay
if(needle === "") return true;
// but in all other cases, falsey values were considered false
if(!needle) return false;
// our mission, to find the needle in the haystack - is this tacky?
var haystack = this;
// primarily here to prevent AIOOBEs in the loop - is this the most
// JavaScripty way to preempt that error?
if(needle.length > haystack.length) {
return false;
}
// I've read that 'i' is not scoped to this for loop, and that I would
// need let instead. I must support older browsers, is there a better
// way to do this?
for(var i = 0; i < needle.length; i++) {
if(haystack.charAt(i) !== needle.charAt(i)) {
return false;
}
}
return true;
}
1 Answer 1
I'd suggest using String.prototype.slice to implement startsWith
like this:
String.prototype.startsWith = function(str) {
return this.slice(0, str.length) === str
}
For type-checking (not needed in this example, but generally speaking) you might want to use the typeof
operator:
if (typeof str !== 'string') return false
You can also use the instanceof
operator if the value your dealing w/ isn't a literal or you need to check every value in the prototype chain, e.g. str instanceof String
haystack = this
? Super-tacky ;p, but each to their own
Not sure if JS has an AIOOBE equivalent but 'blah'.charAt(6) === ''
which tells me that check isn't needed.
And I'd suggest using Array iterators rather than for loops in the future:
var haystackStartsWithNeedle = needle.split('').
forEach((v,i) => v === haystack[i]).find(v => v)
You might want to check babeljs.io. It transpiles new & flavoured JS to code most browsers can use.
-
\$\begingroup\$ Modifying native prototypes is generally a bad idea, especially if you're overwriting existing methods or prototypes which could be confused w/ others (Promise vs Promise-like object for example) \$\endgroup\$Ashton Six– Ashton Six2016年02月03日 12:59:30 +00:00Commented Feb 3, 2016 at 12:59
-
\$\begingroup\$ About the AIOOBE you're right that it wouldn't error out, and would still work correctly - but if my needle is bigger than my haystack, I know the result is false. And isn't needle and haystack the common terms to use when searching? I thought it was - if there's better names, I'm open to that. With regards to modifying native prototypes, is this just because if everyone modifies native prototypes, you lose assurance that you're dealing with the original code? I'm not overwriting an existing method (otherwise I wouldn't write one!) and I'm not sure what you mean about "confused w/ others". \$\endgroup\$corsiKa– corsiKa2016年02月04日 16:14:13 +00:00Commented Feb 4, 2016 at 16:14
-
\$\begingroup\$ Yes, you know the result is false - but the check only adds complexity & optimization is best left to the optimizer (unless dramatic or big O related). You can totally use needle & haystack, just seems kinda weird to me - personal taste. Modifying native prototypes can go wrong in a few different situations - particularly name collision when multiple people working on a codebase are creating custom methods. W/ promises specifically there's a lot of different implementations & b/c JS is dynamically typed you can't be certain which objects have which methods until runtime. \$\endgroup\$Ashton Six– Ashton Six2016年02月04日 20:04:19 +00:00Commented Feb 4, 2016 at 20:04
-
\$\begingroup\$ Example I just found: b/c MooTools (a popular library) modifies the Array prototype we've not been able to implement Array.prototype.contains in the language itself - esdiscuss.org/topic/… \$\endgroup\$Ashton Six– Ashton Six2016年02月07日 16:09:50 +00:00Commented Feb 7, 2016 at 16:09