Javascript截取字符串函数比较

JavaScript 字符串截取函数对比

字符串截取是前端开发中最常用的操作之一——处理用户输入、提取URL参数、生成文本摘要、截取文件名……几乎每天都要用到。但JavaScript里的截取函数有好几个,slice()substring()、还有已经废弃的substr(),很多人经常搞混它们的区别,尤其是对负数参数的处理,一不小心就踩坑。
今天就把这几个函数的语法、区别、使用场景、避坑指南全部分享出来,一篇文章帮你彻底搞懂字符串截取。

一、先搞懂:JavaScript 有哪些常用的字符串截取函数?

JavaScript 中用于截取字符串的核心函数有三个(按推荐程度排序):

  1. **slice()**:最推荐,最灵活,对负数参数支持最好;
  2. **substring()**:经典方法,参数规则特殊,不支持负数索引;
  3. **substr()**:已废弃(ECMAScript 标准已移除),但老代码中仍常见,不推荐在新项目中使用。

重要前提:所有这些方法都不会修改原字符串,而是返回一个新的截取后的字符串,这是字符串不可变特性的体现。

二、逐个详解:语法、参数与实战例子

1. slice():最推荐的全能选手

slice() 是目前最推荐使用的字符串截取方法,它的语法直观,对负数参数的处理符合直觉,几乎能覆盖所有场景。

语法

1
str.slice(startIndex, endIndex)
  • **startIndex**:必需,截取的起始索引(包含该位置的字符);
  • **endIndex**:可选,截取的结束索引(不包含该位置的字符);如果省略,默认截取到字符串末尾。

核心特点

  • 支持负数索引:负数表示从字符串末尾开始计数,-1 是最后一个字符,-2 是倒数第二个,以此类推;
  • 如果 startIndex > endIndex,返回空字符串
  • 不修改原字符串。

实战例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const str = 'Hello, RequireJS!'; // 长度16,索引0-15

// 1. 基本用法:从索引2截取到索引7(不包含7)
console.log(str.slice(2, 7)); // 'llo, '

// 2. 省略 endIndex:从索引7截取到末尾
console.log(str.slice(7)); // 'RequireJS!'

// 3. 使用负数索引:从倒数第6个截取到倒数第1个
console.log(str.slice(-6, -1)); // 'ireJS'

// 4. 负数 + 正数混合:从索引2截取到倒数第6个
console.log(str.slice(2, -6)); // 'llo, Req'

// 5. startIndex > endIndex:返回空字符串
console.log(str.slice(7, 2)); // ''

2. substring():经典但规则特殊

substring() 是早期 JavaScript 中常用的截取方法,它的参数规则比较特殊,尤其是对负数和参数顺序的处理,容易踩坑。

语法

1
str.substring(startIndex, endIndex)
  • **startIndex**:必需,截取的起始索引(包含该位置的字符);
  • **endIndex**:可选,截取的结束索引(不包含该位置的字符);如果省略,默认截取到字符串末尾。

核心特点

  • 不支持负数索引:任何负数参数都会被自动转换为 0
  • 如果 startIndex > endIndex,会自动交换两个参数的位置;
  • 不修改原字符串。

实战例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const str = 'Hello, RequireJS!';

// 1. 基本用法:和 slice() 一致
console.log(str.substring(2, 7)); // 'llo, '

// 2. 省略 endIndex:和 slice() 一致
console.log(str.substring(7)); // 'RequireJS!'

// 3. 负数参数:自动转换为 0
console.log(str.substring(-6, 7)); // 等价于 substring(0,7) → 'Hello, '
console.log(str.substring(2, -1)); // 等价于 substring(2,0) → 自动交换为 substring(0,2) → 'He'

// 4. startIndex > endIndex:自动交换参数
console.log(str.substring(7, 2)); // 等价于 substring(2,7) → 'llo, '

3. substr():已废弃,不推荐使用

substr() 的语法和前两个不同,它是通过「起始索引 + 截取长度」来截取的,虽然很多浏览器还支持,但 ECMAScript 标准已经将其移除,新项目绝对不要用,仅在维护老代码时了解即可。

语法

1
str.substr(startIndex, length)
  • **startIndex**:必需,截取的起始索引(包含该位置的字符);支持负数(从末尾开始计数);
  • length:可选,截取的字符长度;如果省略,默认截取到字符串末尾;不能为负数

核心特点

  • 已废弃,不推荐使用;
  • startIndex 支持负数,但 length 不支持负数;
  • 不修改原字符串。

实战例子

1
2
3
4
5
6
7
8
9
10
11
12
13
const str = 'Hello, RequireJS!';

// 1. 基本用法:从索引2开始,截取5个字符
console.log(str.substr(2, 5)); // 'llo, '

// 2. 省略 length:从索引7截取到末尾
console.log(str.substr(7)); // 'RequireJS!'

// 3. startIndex 为负数:从倒数第6个开始,截取5个字符
console.log(str.substr(-6, 5)); // 'ireJS'

// 4. length 为负数:返回空字符串(部分浏览器可能报错)
console.log(str.substr(2, -5)); // ''

三、核心对比:一张表搞懂所有区别

为了更直观地对比,我把三个方法的核心差异整理成了表格:

特性 slice() substring() substr()(已废弃)
参数规则 (start, end) (start, end) (start, length)
负数 start 从末尾计数(-1=最后一个) 自动转换为 0 从末尾计数(-1=最后一个)
负数 end/length 从末尾计数 自动转换为 0 返回空字符串(或报错)
start > end 返回空字符串 自动交换参数位置 正常截取(只要 length 合法)
是否废弃 ❌ 否(推荐使用) ❌ 否(可用但不推荐优先) ✅ 是(ECMAScript 已移除)
推荐指数 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐(仅老代码维护)

四、使用场景建议:什么时候用哪个?

1. 优先使用 slice()(90%的场景都选它)

slice() 是最灵活、最符合直觉的方法,以下场景优先用它:

  • 需要从字符串末尾截取(用负数索引,比如截取文件后缀名:str.slice(-3));
  • 参数可能是动态计算的(不用担心 start > end 的问题,直接返回空字符串,逻辑更可控);
  • 代码可读性要求高(负数索引的语义更清晰)。

典型例子:截取文件后缀名

1
2
3
const filename = 'document.pdf';
const ext = filename.slice(filename.lastIndexOf('.'));
console.log(ext); // '.pdf'

2. 谨慎使用 substring()(仅在特殊场景)

substring() 可以用,但不是首选,仅在以下场景考虑:

  • 维护老代码,原有逻辑已经用了 substring()
  • 需要「自动交换参数」的特性(虽然这个特性很容易导致逻辑混乱)。

3. 绝对不要用 substr()(新项目禁止)

substr() 已经被标准废弃,虽然浏览器还支持,但随时可能有兼容性问题,新项目一律不要用,老代码也建议逐步替换为 slice()

五、避坑指南:90%的人都会踩的坑

1. 混淆 slice() 和 substring() 的负数处理

这是最常见的坑!比如想从倒数第3个字符截取到末尾:

1
2
3
4
5
6
7
const str = 'abcdef';

// 正确:slice() 支持负数
console.log(str.slice(-3)); // 'def'

// 错误:substring() 把 -3 转成 0,结果是整个字符串
console.log(str.substring(-3)); // 'abcdef'

2. 忘记字符串索引从 0 开始

字符串的索引是从 0 开始的,不是 1,这是新手最容易犯的错误:

1
2
3
4
const str = 'Hello';
// 想截取 'ell',但索引写错了
console.log(str.slice(1, 4)); // 'ell'(正确:索引1-4,包含1不包含4)
console.log(str.slice(2, 5)); // 'llo'(错误)

3. 以为这些方法会修改原字符串

再次强调:所有字符串截取方法都不会修改原字符串,必须用变量接收返回值:

1
2
3
4
5
6
const str = 'Hello, World!';
str.slice(0, 5); // 错误:没有接收返回值,原字符串没变
console.log(str); // 'Hello, World!'

const newStr = str.slice(0, 5); // 正确:用变量接收
console.log(newStr); // 'Hello'

4. substr() 的 length 参数为负数

虽然部分浏览器会返回空字符串,但这是未定义行为,绝对不要这么写:

1
2
const str = 'abcdef';
console.log(str.substr(2, -3)); // 错误:length 不能为负数

六、扩展:除了这三个,还有哪些截取技巧?

除了上面的核心方法,还有一些常用的截取技巧,配合其他字符串/数组方法使用,能解决更复杂的场景:

1. 截取指定字符之前/之后的内容

结合 indexOf()lastIndexOf()

1
2
3
4
5
6
7
8
9
const url = 'https://www.example.com/path?query=123';

// 截取 ? 之前的内容(域名+路径)
const baseUrl = url.slice(0, url.indexOf('?'));
console.log(baseUrl); // 'https://www.example.com/path'

// 截取 ? 之后的内容(查询参数)
const query = url.slice(url.indexOf('?') + 1);
console.log(query); // 'query=123'

2. 按分隔符截取(split() + 数组操作)

如果需要按特定字符(如逗号、空格)截取成多段,用 split() 更方便:

1
2
3
4
5
6
7
8
const str = 'apple,banana,orange';

// 按逗号截取成数组
const arr = str.split(',');
console.log(arr); // ['apple', 'banana', 'orange']

// 取第二段
console.log(arr[1]); // 'banana'

3. ES6+ 的字符串方法补充

  • startsWith() / endsWith():判断字符串是否以某字符开头/结尾(配合截取使用);
  • includes():判断字符串是否包含某字符;
  • padStart() / padEnd():补全字符串(虽然不是截取,但常和截取配合)。

七、总结

最后给大家一个最终的使用建议:

  1. **90%的场景,直接用 slice()**:它最灵活,对负数支持最好,逻辑最清晰;
  2. 维护老代码时,substring() 可以保留,但不要在新逻辑中用
  3. substr() 彻底放弃:新项目绝对不要用,老代码逐步替换为 slice()
  4. 复杂场景配合 indexOf()split() 等方法:不要只盯着截取函数,组合使用效率更高。

字符串截取虽然是小功能,但细节很多,掌握好它,以后再也不会在这个问题上踩坑!


Javascript截取字符串函数比较
https://cszy.top/2016-01-06 javascript截取字符串函数比较/
作者
csorz
发布于
2016年1月6日
许可协议