substring和substr的区别

你可曾和我一样,想截个字符串,在用IDE的或者在浏览器控制台打somestr.subs...的时候,弹出两个提示项,一个是substring,另一个还是subtring,哦不好意思,另一个是substr,然后你就两眼瞪得跟牛一样,不知道该选哪个?然后就会随便选一个试一下,如果是自己想要的结果,‘就选她~’。

嗯,这样不好,今天咱来好好认识一下这两位长得很像的家伙。

substring

str.substring(idxStart[,idxEnd])

  • idxStart: 要截取字符串的起始位置。
  • idxEnd: 要截取的字符串的截止位置,「它是个可选参数」。

好,那既然是参数就可以(可能)被乱填或者不填,那样会报错吗?告诉你,一般不会。那substring这货会怎么处理你「乱写」的参数呢? MDN说了:

  • 如果indxStart等于indexEnd,返回空。
  • 如果indexEnd不写,截到字符串的尾部。相当于indexEnd等于字符串的长度值。
  • 如果两个参数的任何一个小于0或者等于NaN,那该参数当作0处理。
  • 如果任何一个参数大于字符串的长度值,那它就当作等于字符串长度处理。
  • 如果indexStart比indexEnd还要大,那就把两个参数调换过来处理。

举几个栗子来验证一下:

var anyString = 'Mozilla';

// Displays 'Moz'
console.log(anyString.substring(0, 3));  
console.log(anyString.substring(3, 0));

// Displays 'lla'
console.log(anyString.substring(4, 7));  
console.log(anyString.substring(7, 4));

// Displays 'Mozill'
console.log(anyString.substring(0, 6));

// Displays 'Mozilla'
console.log(anyString.substring(0, 7));  
console.log(anyString.substring(0, 10));

//Display 'Mo'
anyString.substring(-2,2);

//Display ''
anyString.substring(-2,-1)

substr

str.substr(idxStart[, length])

  • idxStart:截取的起始位置。
  • length:截取长度。「它是个可选参数」。

从参数含义可以看出这两个家伙的本质区别。就是第二个参数的意义不同。substr的第二个参数是关心的是要截多少个字符,而不关心你截到哪儿(它仿佛高傲在说:截到哪儿?自己算呗~)。所以,我们还是来看一下,substr的参数可以怎么「乱写」,以及「乱写」之后它是怎么处理它们的。MDN上又说了:

  • 如果idxStart大于或等于字符串本身的长度的话,substr返回空字符串;
  • 如果idxStart是负数,那么它相当于倒数的位置,比如-3,就是倒数第三的位置;
  • 那么如果idxStart是负数而且负得比字符串的长度还多呢?那substr会直接把它当作0来处理;
  • 如果length是0或者负数,substr会直接返回0;
  • 如果length省略的话,substr会截到字符串的尾数为止;

举几个栗子来验证一下:

var str = 'abcdefghij';

console.log('(1, 2): '   + str.substr(1, 2));   // '(1, 2): bc'  
console.log('(-3, 2): '  + str.substr(-3, 2));  // '(-3, 2): hi'  
console.log('(-3): '     + str.substr(-3));     // '(-3): hij'  
console.log('(1): '      + str.substr(1));      // '(1): bcdefghij'  
console.log('(-20, 2): ' + str.substr(-20, 2)); // '(-20, 2): ab'  
console.log('(20, 2): '  + str.substr(20, 2));  // '(20, 2): '  

注意

微软的JScript是不支持负数值作为idxStart值的。如果是那样的话,可以通过下面的这段代码「修复」一下:

// only run when the substr() function is broken
if ('ab'.substr(-1) != 'b') {  
  /**
   *  Get the substring of a string
   *  @param  {integer}  start   where to start the substring
   *  @param  {integer}  length  how many characters to return
   *  @return {string}
   */
  String.prototype.substr = function(substr) {
    return function(start, length) {
      // call the original method
      return substr.call(this,
          // did we get a negative start, calculate how much it is from the beginning of the string
        // adjust the start parameter for negative value
        start < 0 ? this.length + start : start,
        length)
    }
  }(String.prototype.substr);

总结一下

由此我们知道,substringsubstr功能相同,用法完全不同的两个string函数。那么有人会说,有时候我用它们两个,参数一样结果也完全一样。是的,是有这种情况,当你要截取的起始位置是0,然后第二个参数又是正数的话,它们的作用和结果是完全一样的。还有当起始位置是不小于长度的正数,尾数不写,结果也是一样的。那么为什么发明js的人,要搞两个长得那么像,功能又相同的函数呢?害得我们经常认错。我的理解是:

  • 当你方便获取截取区间的时候用substring。这里就不举栗子了,大概是在你的程序里,写到要截字符串的时候,你发现你上下文已经有(或者方便拿)要截取的区间(尤其是截取终止位置)的时候,就用它最顺手了。比如str.substring(start,end)明显比str.substr(start,start+end)要方便。

  • 当你更清楚自己想截多少个字符的时候用substr更方便。比如,你想截尾部三个字符:str.substr(-3),这样写又简单又明了。比str.substring(str.length-3)要方便很多。