Skip to content

Commit adb6479

Browse files
Merge pull request #96 from victor-homyakov/patch-33
Use native `String#startsWith` and `String#endsWith` if present. Turn existing implementation into a true polyfill.
2 parents 4ce0b0f + bc3ac95 commit adb6479

File tree

2 files changed

+48
-9
lines changed

2 files changed

+48
-9
lines changed

src/prototype/lang/string.js

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -770,33 +770,47 @@ Object.extend(String.prototype, (function() {
770770
}
771771

772772
/**
773-
* String#startsWith(substring) -> Boolean
773+
* String#startsWith(substring[, position]) -> Boolean
774+
* - substring (String): The characters to be searched for at the start of this string.
775+
* - [position] (Number): The position in this string at which to begin searching for `substring`; defaults to 0.
774776
*
775777
* Checks if the string starts with `substring`.
776778
*
777779
* ##### Example
778780
*
779781
* 'Prototype JavaScript'.startsWith('Pro');
780782
* //-> true
783+
* 'Prototype JavaScript'.startsWith('Java', 10);
784+
* //-> true
781785
**/
782-
function startsWith(pattern) {
786+
function startsWith(pattern, position) {
787+
position = Object.isNumber(position) ? position : 0;
783788
// We use `lastIndexOf` instead of `indexOf` to avoid tying execution
784789
// time to string length when string doesn't start with pattern.
785-
return this.lastIndexOf(pattern, 0) === 0;
790+
return this.lastIndexOf(pattern, position) === position;
786791
}
787792

788793
/**
789-
* String#endsWith(substring) -> Boolean
794+
* String#endsWith(substring[, position]) -> Boolean
795+
* - substring (String): The characters to be searched for at the end of this string.
796+
* - [position] (Number): Search within this string as if this string were only this long;
797+
* defaults to this string's actual length, clamped within the range established by this string's length.
790798
*
791799
* Checks if the string ends with `substring`.
792800
*
793801
* ##### Example
794802
*
795803
* 'slaughter'.endsWith('laughter')
796804
* // -> true
805+
* 'slaughter'.endsWith('laugh', 6)
806+
* // -> true
797807
**/
798-
function endsWith(pattern) {
799-
var d = this.length - pattern.length;
808+
function endsWith(pattern, position) {
809+
pattern = String(pattern);
810+
position = Object.isNumber(position) ? position : this.length;
811+
if (position < 0) position = 0;
812+
if (position > this.length) position = this.length;
813+
var d = position - pattern.length;
800814
// We use `indexOf` instead of `lastIndexOf` to avoid tying execution
801815
// time to string length when string doesn't end with pattern.
802816
return d >= 0 && this.indexOf(pattern, d) === d;
@@ -878,8 +892,9 @@ Object.extend(String.prototype, (function() {
878892
isJSON: isJSON,
879893
evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
880894
include: include,
881-
startsWith: startsWith,
882-
endsWith: endsWith,
895+
// Firefox 18+ supports String.prototype.startsWith, String.prototype.endsWith
896+
startsWith: String.prototype.startsWith || startsWith,
897+
endsWith: String.prototype.endsWith || endsWith,
883898
empty: empty,
884899
blank: blank,
885900
interpolate: interpolate

test/unit/string_test.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,11 @@ new Test.Unit.Runner({
430430
this.assert(!'hello world'.startsWith('bye'));
431431
this.assert(!''.startsWith('bye'));
432432
this.assert(!'hell'.startsWith('hello'));
433+
434+
var str = "To be, or not to be, that is the question";
435+
this.assert(str.startsWith("To be"), 'str.startsWith("To be")');
436+
this.assert(!str.startsWith("not to be"), 'str.startsWith("not to be")');
437+
this.assert(str.startsWith("not to be", 10), 'str.startsWith("not to be", 10)');
433438
},
434439

435440
testEndsWith: function() {
@@ -439,6 +444,25 @@ new Test.Unit.Runner({
439444
this.assert(!''.endsWith('planet'));
440445
this.assert('hello world world'.endsWith(' world'));
441446
this.assert(!'z'.endsWith('az'));
447+
448+
var str = "To be, or not to be, that is the question";
449+
this.assert(str.endsWith("question"), 'str.endsWith("question")');
450+
this.assert(!str.endsWith("to be"), 'str.endsWith("to be")');
451+
this.assert(str.endsWith("to be", 19), 'str.endsWith("to be", 19)');
452+
453+
str = "12345";
454+
this.assert(str.endsWith("5"));
455+
this.assert(str.endsWith("5", 6));
456+
this.assert(str.endsWith("5", 5));
457+
this.assert(!str.endsWith("5", 4));
458+
this.assert(!str.endsWith("5", 1));
459+
this.assert(!str.endsWith("5", 0));
460+
461+
this.assert(str.endsWith("1", 1));
462+
this.assert(!str.endsWith("1", 0));
463+
this.assert(!str.endsWith("1", -1));
464+
465+
this.assert(str.endsWith("", 0));
442466
},
443467

444468
testBlank: function() {
@@ -551,4 +575,4 @@ new Test.Unit.Runner({
551575
this.assertIdentical(false, 'false'.evalJSON());
552576
this.assertEqual('"', '"\\""'.evalJSON());
553577
}
554-
});
578+
});

0 commit comments

Comments
 (0)