为什么在历史上' substring '已经存在时要添加' substr '

Why historically was `substr` added when `substring` already existed?

本文关键字:添加 substr 存在 在历史上 substring 为什么      更新时间:2023-09-26

我知道substr(start[, length])substring(start[, end])之间的区别。这在前面的问题中得到了解决:substr和substring之间的区别是什么?

但是为什么substring已经存在的情况下才添加substr ?我想知道这个决定的历史。

我发现substring从一开始就在那里,然后"突然"在Ecmascript第三版中,他们有两个不同的函数来用不同的参数实现完全相同的事情。为什么?

如果没有十年前参与ECMA的人参与,我认为我们不能明确地回答这个问题,但我们可以推断出一些事情。

substring请求从0开始的索引,也可以选择从0开始的索引。

substr请求起始点的索引(从0开始)和长度。这使得它在某些情况下更容易使用,例如,如果你想从第一个"s"中获取2个字符,你可以指定2作为长度,而不是必须首先计算第一个"s"的索引,然后加上2,然后将两个位置传递给substring

正如在评论中指出的,substr允许负起始位置。

可以说,substr是一个更好的实现。所以这很可能就是为什么它被添加。

至于为什么两者都在那里的问题,这可能是为了向后兼容。因为Javascript运行在各种各样的浏览器中(现在也运行在其他地方),在由多个组织维护的运行时中,没有简单的方法来弃用或消除任何东西。更简单的做法是把它留在那里,然后添加更多的内容到语言中。旧代码仍然可以工作,新代码有更好的选项可供使用。

这两个函数的用例是不同的。

String.prototype.substr()允许您使用负起始值从字符串的末尾获取子字符串,这使得它适合于一些更多的用例,而不会生成过于冗长,不可读的代码。

// alert('1234567890'.substring('1234567890'.length - 4)) <-- UGLY
alert('1234567890'.substr(-4))
仅凭这一点,它就使得问题中函数实现完全相同的事情的假设完全错误,这与问为什么存在任何其他函数没有什么不同。唯一能回答这个问题的人就是做这个决定的人。

正如所说,它们并不相同,它们只是可以做一些共同的操作。事实上,他们完成工作的内部步骤也各不相同。以下是Ecma International网站上的一些引用:

B.2.3 String.prototype.substr (start, length) substr方法接受两个参数,startlength,并返回a将this对象转换为String对象的结果的子字符串;从字符位置开始并运行长度(如果长度undefined,则通过字符串的末尾)。如果start为负,则将其处理为(sourceLength+start),其中sourceLength是字符串的长度。结果是一个String值,而不是字符串对象。执行以下步骤:
  1. 调用ToString,给它这个值作为参数。
  2. 调用ToInteger (开始)。
  3. 如果长度定义,使用+∞;否则调用ToInteger(length)。
  4. 计算结果(1)中的字符数
  5. 如果Result(2)为正或为零,则使用Result(2);
  6. 使用max(Result(4)+Result(2),0)。
  7. 计算最小(最大(结果(3),0),结果(4)结果(5))。
  8. 如果结果(6)≤0,返回空字符串" "
  9. 返回一个字符串,包含Result(1)中的6个连续字符,以位置Result(5)的字符开始。
substr方法的length属性为2

注意:substr函数故意是通用的;它不要求它的this值是String对象。因此它可以是传递给其他类型的对象作为方法使用。

15.5.4.15 String.prototype.substring (start, end)

子字符串方法接受两个参数,startend,并返回a将此对象转换为字符串的结果的子字符串,从字符位置开始运行到,但不是包括字符位置,结束的字符串(或通过的结束end is undefined)。结果是一个String值,而不是字符串对象。

如果参数为NaN或负值,则将其替换为零;如果任何一个参数都大于String的长度,是的

如果start大于end,它们被交换。

执行以下步骤:

  1. 调用CheckObjectCoercible,传递this值作为参数。
  2. 让S是调用ToString的结果,给它这个值作为参数。
  3. len为s中的字符数。
  4. intStart为ToInteger(start)。
  5. 如果end未定义,则设置 intent 为len;else let intent be ToInteger(end).
  6. finalStart 是min (max ( intStart 0), len )。
  7. finalEnd 是min (max (意愿 0), len )。
  8. 是最小值( finalStart , finalEnd )。
  9. max ( finalStart , finalEnd )。
  10. 返回一个长度从 - 的String,包含S中的字符,即从−1的下标字符,按升序排列。
子字符串方法的length属性为2

注意:子字符串函数故意是通用的;事实并非如此要求它的this值是String对象。因此,它可以是传递给其他类型的对象作为方法使用。

所以底线是它们不是相同的方法,它们的用法也不相同。

substr允许从末尾提取子字符串,如:"Good news, everyone!".substr(-4);将返回one!。(IE8不支持)。由于JavaScript不支持函数重载。所以我的理论是,这个从末尾提取子字符串的功能是社区非常需要的,因此他们引入了类似的功能,只是有一点变化。我不知道真正的原因是什么,但据我所知,缺乏对函数重载的原生支持可能导致了这个substr函数的诞生。

为什么?因为方便。

大概。如果不询问这个决定的原作者,就没有办法知道确切的答案。

但是我们只能假设它是基于类似于导致在Visual Basic中具有例如函数LeftRight的推理,即使使用具有不同参数组合的Mid函数可以获得相同的结果,尽管不太方便并且需要更多或更长的代码行。(或者,用自己喜欢的语言找个比喻)

例如,使用substrlength参数代替substringend参数可以获得一些轻微的可读性/简洁性增益:
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!! ---------->

或者,当使用substring时,您可以将test.indexOf("Second")存储在一个临时变量中以缩短substring调用:

var n = test.indexOf("Second");
alert(test.substring(n, n + 'Second'.length)) 

,但这是多一行代码和一个额外的温度,你不需要使用substr

底线:这真的没什么大不了的!为了方便起见,他们又增加了一个功能。