Skip to content Skip to sidebar Skip to footer

Why Historically Was `substr` Added When `substring` Already Existed?

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 an

Solution 1:

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.

Solution 2:

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 substring.

As was pointed out in a comment, substr allows a negative starting position.

Arguably, substr is a better implementation. And so that is quite possibly why it was added.

As to the question of why are both there, that is probably for backward compatibility. Because Javascript runs in a wide variety of browsers (and these days elsewhere), in runtimes maintained by multiple organizations, there is no easy way to deprecate or eliminate anything. It's easier to just leave it there and add more to the language instead. Old code still works, and new code has better options available to use.

Solution 3:

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:

  1. Call ToString, giving it the this value as its argument.
  2. Call ToInteger(start).
  3. If length is undefined, use +∞; otherwise call ToInteger(length).
  4. Compute the number of characters in Result(1).
  5. If Result(2) is positive or zero, use Result(2); else use max(Result(4)+Result(2),0).
  6. Compute min(max(Result(3),0), Result(4)–Result(5)).
  7. If Result(6) ≤ 0, return the empty String “”.
  8. 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.

and

15.5.4.15 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:

  1. Call CheckObjectCoercible passing the this value as its argument.
  2. Let S be the result of calling ToString, giving it the this value as its argument.
  3. Let len be the number of characters in S.
  4. Let intStart be ToInteger(start).
  5. If end is undefined, let intEnd be len; else let intEnd be ToInteger(end).
  6. Let finalStart be min(max(intStart, 0), len).
  7. Let finalEnd be min(max(intEnd, 0), len).
  8. Let from be min(finalStart, finalEnd).
  9. Let to be max(finalStart, finalEnd).
  10. 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.

Solution 4:

substr allows extracting sub-string from the end like: "Good news, everyone!".substr(-4); will return one!. (Not supported by IE8- though). And since JavaScript doesn't natively support Function Overloading. So my theory is that this feature of extracting sub-string from the end was demanded heavily by the community and hence they introduced similar function with another name with a little change. I don't know what was the real reason but according to me the absence of native support for function overloading may caused the birth of this substr function.

Solution 5:

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 Left and 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 substring call:

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 substr.

Bottom line: It's really no big deal! They added one more function for slightly more convenience.

Post a Comment for "Why Historically Was `substr` Added When `substring` Already Existed?"