只要有 substring 和 slice,就没什么好怕的。
在加入了陈年专案维护中获得了新知识。
前言
最近工作派发了一些 Legacy Code 专案翻修,难免会遇到一些 deprecated 的方法。
面对这些陈年代码,最大的敌人往往都是疏忽了商业逻辑以及代码可读性。
本篇重点不在于介绍 substr, substring, slice ,想必大家都略懂这方法。
如果使用冷门特性,你一辈子都会记得写注解对吧!?
这一篇的角度在于笔者对 Legacy Code 进行 String.substr() 重构的思路。
从「维护性」与「效能」的之间找到合适的平衡。
这份笔记也是为了日后仍遇到时,可以快速拿自己的文章参考。
希望能对大家有所帮助。
一、字串切割介绍
简单说明一下他们「主要」的用法。
最大的区别在于第二个参数「索引 Index」的意义。
String.prototype.substr() - MDN Web Docs
substr(start)
substr(start, length)String.prototype.substring() - MDN Web Docs
substring(indexStart)
substring(indexStart, indexEnd)String.prototype.slice() - MDN Web Docs
slice(indexStart)
slice(indexStart, indexEnd)
这些方法中,最大的差异在于:
- 参数使用几个?
- 传入的参数值是否为 ≥ 0?
- 传入的参数值是否为 负数?
二、评估抽换方式
这篇是解决 Legacy Code 的场景,因此可以思考你面对的 substr() ,是为了解决什么问题?
接着来探索这些可能的条件,找出最适的解决方案!
极端的例子我相信是鲜少的,不太需要执着于极端案例。
难以长期传承商业逻辑的代码,最需要的是直观的可读性。
以下提供 7 种的例子,作为重构的选择:
- 基本使用
substr(start, length)) - 起始索引为负数
substr(-start, length)→ 使用slice() - 长度超过字串长度
substr(start, length)→ 使用substring() - 起始索引超过字串长度
substr(start, length)→ 使用slice() - 单参数
substr(start)→ 使用substring() - 起始索引为负数且超过字串长度
substr(-start, length)→ 使用slice() - 无法使用
substring(start, end)替代substr()的情境 → 使用slice()
1 . 基本使用 substr(start, length)
适用于简单的範围撷取,用于单纯的商业逻辑。
const str = "JavaScript";
console.log(str.substring(4, 10)); // "Script"使用 substring() 替换。
console.log(str.substring(4, 10)); // "Script"✅ substring(start, start + length) 直观表达了「从 start 位置撷取 length 个字元」,可读性极高。
2. 起始索引为负数 substr(-start, length) → 使用 slice()
substring() 不支援负数索引,因此需要 slice() 来替代。
const str = "Hello World";
console.log(str.slice(-5)); // "World"使用 slice() 替换。
console.log(str.slice(-5)); // "World"✅ slice(-start) 直接从倒数第 start 个字元开始撷取,行为与 substr() 相同。
3. 长度超过字串长度 substr(start, length) → 使用 substring()
在一些未知长度的条件下,如果允许 length 超出範围,substr() 会自动调整,substring() 也有类似行为。
const str = "abcdef";
console.log(str.substring(2)); // "cdef"使用 substring() 替换相对直观,slice() 你喜欢也可以使用。
console.log(str.substring(2, str.length)); // "cdef"✅ substring(start, end) 自动处理 end 超过範围的情况。
4. 起始索引超过字串长度 substr(start, length) → 使用 slice()
如果场景具有未知的起始索引,substring() 会自动交换 start 和 end,而有不同结果,这种条件建议使用 slice()。
const str = "Hello";
console.log(str.slice(10, 13)); // "" (空字串)使用 slice() 替换。
console.log(str.slice(10, 13)); // "" (空字串)✅ slice(start, end) 行为与 substr() 一致,会返回空字串。
5. 单参数 substr(start) → 使用 substring()
当 length 省略时,substr(start) 会提取到字串结尾,这与 substring(start) 行为相同。这应该是最简单的场境,单纯且单一参数。
const str = "Hello JavaScript";
console.log(str.substring(6)); // "JavaScript"使用 substring() 替换。
console.log(str.substring(6)); // "JavaScript"✅ substring(start) 直觉地表示「从 start 开始到字串结尾」,可读性高。
6. 起始索引为负数且超过字串长度 substr(-start, length) → 使用 slice()
通常在于更多的演算方法。substring() 不支援负数索引,应该使用 slice()。
const str = "Hello";
console.log(str.slice(-10, -7)); // "Hel"使用 slice() 替换。
console.log(str.slice(-10, -7)); // "Hel"✅ slice(start, end) 在负索引时表现一致,适用于此场景。
7. 无法使用 substring(start, end) 替代 substr() 的情境 → 使用 slice()
substring() 无法处理负数索引,也无法撷取固定长度,因此 slice() 是更好的选择。
const str = "Hello World";
console.log(str.slice(-5, -2)); // "Wor"错误的 substring() 替换。
console.log(str.substring(0, 3)); // "" (错误,因为 `substring()` 会将负数视为 0)正确的做法应该用 slice()。
console.log(str.slice(-5, -2)); // "Wor"✅ slice() 是唯一能够完全取代 substr() 在负索引情境下的选择。
三、结论
整体而言,应该根据重构的目的,以及代码的职责来决定适合哪一种。
- 基于可读性优先:如果今天你在业务逻辑单纯,且索引範围固定时,
substring()可读性更高。 - 基于效率且容错率高的场景:如果面对特定的演算或者複杂的计算,甚至索引可能是负数等等不稳定的条件,这时候使用
slice()相对安全。
适合 substring() 的场景:
- start 与 end 你能肯定商业逻辑为正数。
- 需要撷取 固定範围,不考虑负索引。
- 可读性佳,适用于基本的字串撷取。
适合 slice() 的场景:
- 需要支援负数索引
substr(-start, length)。 - 起始索引超出字串长度时,应返回空字串。
- 避免 start > end 情境时自动交换。
有勘误之处,不吝指教。ob'_'ov

微信扫一扫打赏
支付宝扫一扫打赏