I know what the difference is between
substr(start[, length]) and
substring(start[, end]). This is addressed e.g. in this earlier question: What is the difference between substr and substring?
But why did they add
substr later when
substring was already present? I am looking for information about the history of this decision.
I have found that
substring was there from the beginning and then 'suddenly' in Ecmascript 3rd edition they have two different functions to achieve the exact same thing with different arguments. Why?
Use cases for the 2 functions are different.
String.prototype.substr() lets you take a substring from the end of the string using negative start value which makes it suitable for some more use cases without generating overly verbose, unreadable code.
// alert('1234567890'.substring('1234567890'.length - 4)) <-- UGLY alert('1234567890'.substr(-4))
By that alone it makes the assumption in the question that the functions achieve the exact same thing simply wrong, and that makes it no different then asking why any other function exist. The only people who can answer such a question are the ones who made that decision.
I don't think we can definitively answer this without someone involved with ECMA ten years ago weighing in, however we can infer some things.
substring asks for the index (from 0) of the start, and optionally an index (again from 0) of the end.
substr asks for the index (from 0) of the start, and a length. That makes it simpler to use for some cases, e.g. if you want to fetch 2 characters from the first "s" you can just specify 2 as the length instead of having to first calculate the index of the first "s" and then adding 2 to that, and then passing both positions to
As was pointed out in a comment,
substr allows a negative starting position.
substr is a better implementation. And so that is quite possibly why it was added.
As told, they are not the same, they just can do some operations in common. In fact, their internal steps to complete the work are also different from each other. Here are some quotes from Ecma International's site:
B.2.3 String.prototype.substr (start, length)
The substr method takes two arguments, start and length, and returns a substring of the result of converting the this object to a String, starting from character position start and running for length characters (or through the end of the String if length is undefined). If start is negative, it is treated as (sourceLength+start) where sourceLength is the length of the String. The result is a String value, not a String object. The following steps are taken:
- Call ToString, giving it the this value as its argument.
- Call ToInteger(start).
- If length is undefined, use +?; otherwise call ToInteger(length).
- Compute the number of characters in Result(1).
- If Result(2) is positive or zero, use Result(2); else use max(Result(4)+Result(2),0).
- Compute min(max(Result(3),0), Result(4)–Result(5)).
- If Result(6) ? 0, return the empty String “”.
- Return a String containing Result(6) consecutive characters from Result(1) beginning with the character at position Result(5).
The length property of the substr method is 2.
NOTE: The substr function is intentionally generic; it does not require that its this value be a String object. Therefore it can be transferred to other kinds of objects for use as a method.
18.104.22.168 String.prototype.substring (start, end)
The substring method takes two arguments, start and end, and returns a substring of the result of converting this object to a String, starting from character position start and running to, but not including, character position end of the String (or through the end of the String is end is undefined). The result is a String value, not a String object.
If either argument is NaN or negative, it is replaced with zero; if either argument is larger than the length of the String, it is replaced with the length of the String.
If start is larger than end, they are swapped.
The following steps are taken:
- Call CheckObjectCoercible passing the this value as its argument.
- Let S be the result of calling ToString, giving it the this value as its argument.
- Let len be the number of characters in S.
- Let intStart be ToInteger(start).
- If end is undefined, let intEnd be len; else let intEnd be ToInteger(end).
- Let finalStart be min(max(intStart, 0), len).
- Let finalEnd be min(max(intEnd, 0), len).
- Let from be min(finalStart, finalEnd).
- Let to be max(finalStart, finalEnd).
- Return a String whose length is to - from, containing characters from S, namely the characters with indices from through to ?1, in ascending order.
The length property of the substring method is 2.
NOTE: The substring function is intentionally generic; it does not require that its this value be a String object. Therefore, it can be transferred to other kinds of objects for use as a method.
So bottom line is neither they are the same methods, nor their usages are the same.
substr allows extracting sub-string from the end like:
"Good news, everyone!".substr(-4); will return
Why? Because convenience.
Presumably. There's no way to know for sure without asking the original authors of this decision.
But we can only assume that it's based on reasoning similar to that which led to having e.g. functions
Right in Visual Basic, even though identical results can be obtained using the
Mid function with a different combination of arguments, albeit less conveniently and with more or longer lines of code. (Or, pick own analogy in own favorite language.)
Fox example, using the
length argument of
substr instead of the
end argument of
substring can lead to some mild readability/conciseness gains:
var test = "First Second Last"; //If you want "Second", do either of: alert(test.substring(test.indexOf("Second"), test.indexOf("Second") + 'Second'.length)) alert(test.substr(test.indexOf("Second"), "Second".length)) //<------ WOW!! ---------->
Alternatively, when using
substring, you could store
test.indexOf("Second") in a temp variable to shorten the
var n = test.indexOf("Second"); alert(test.substring(n, n + 'Second'.length))
but that's one more line of code and one more temp that you don't need when using
Bottom line: It's really no big deal! They added one more function for slightly more convenience.
©2020 All rights reserved.