There seem to be a lot of confusion which was addressed only in comments by elclanrs and raina77ow, so let me post a clarifying answer.
Clarification
From "string.splice
" one may expect that it, like the one for arrays:
- accepts up to 3 arguments: start position, length and (optionally) insertion (string)
- returns the cut out part
- modifies the original string
The problem is, the 3d requirement can not be fulfilled because strings are immutable (related: 1, 2), I've found the most dedicated comment here:
In JavaScript strings are primitive value types and not objects (spec). In fact, as of ES5, they're one of the only 5 value types alongside null
, undefined
, number
and boolean
. Strings are assigned by value and not by reference and are passed as such. Thus, strings are not just immutable, they are a value. Changing the string "hello"
to be "world"
is like deciding that from now on the number 3 is the number 4... it makes no sense.
So, with that in account, one may expect the "string.splice
" thing to only:
- accepts up to 2 arguments: start position, length (insertion makes no sense since the string is not changed)
- returns the cut out part
which is what substr
does; or, alternatively,
- accepts up to 3 arguments: start position, length and (optionally) insertion (string)
- returns the modified string (without the cut part and with insertion)
which is the subject of the next section.
Solutions
If you care about optimizing, you should probably use the Mike's implementation:
String.prototype.splice = function(index, count, add) {
if (index < 0) {
index += this.length;
if (index < 0)
index = 0;
}
return this.slice(0, index) + (add || "") + this.slice(index + count);
}
Treating the out-of-boundaries index may vary, though. Depending on your needs, you may want:
if (index < 0) {
index += this.length;
if (index < 0)
index = 0;
}
if (index >= this.length) {
index -= this.length;
if (index >= this.length)
index = this.length - 1;
}
or even
index = index % this.length;
if (index < 0)
index = this.length + index;
If you don't care about performance, you may want to adapt Kumar's suggestion which is more straight-forward:
String.prototype.splice = function(index, count, add) {
var chars = this.split('');
chars.splice(index, count, add);
return chars.join('');
}
Performance
The difference in performances increases drastically with the length of the string. jsperf shows, that for strings with the length of 10 the latter solution (splitting & joining) is twice slower than the former solution (using slice), for 100-letter strings it's x5 and for 1000-letter strings it's x50, in Ops/sec it's:
10 letters 100 letters 1000 letters
slice implementation 1.25 M 2.00 M 1.91 M
split implementation 0.63 M 0.22 M 0.04 M
note that I've changed the 1st and 2d arguments when moving from 10 letters to 100 letters (still I'm surprised that the test for 100 letters runs faster than that for 10 letters).