JS怎么截取字符串最后两位

作者:小括号时间:2026-11-04 20:08:39浏览:414

在JavaScript中截取字符串最后两位的标准且最简洁的方法是使用 str.slice(-2)。本文系统讲解 slice 负索引底层原理、substring 等传统替代方案的差异、极端边界防御以及包含 Emoji 特殊字符时的处理方案。

JavaScript 教程 标准 ECMAScript 语法 阅读时长约 5 分钟
JS怎么截取字符串最后两位
JavaScript 字符串倒数两位截取图解预览
在 JavaScript 中截取字符串最后两位,最直接、最标准的方法是调用 str.slice(-2)。传入负整数 -2 时,JS 引擎会自动以字符串末尾为基准向前倒数两位,并截取到字符串结束。

一、核心答案与最简代码示例

JavaScript 提供了多个内置的字符串截取方法,但在处理“从尾部倒数提取”这一需求时,String.prototype.slice() 具备无可替代的优势。它原生支持负数作为索引参数,语义极其简洁明了:

// 1. 常规英文字符串截取
const str = "JavaScript";
const lastTwo = str.slice(-2);
console.log(lastTwo); // 输出: "pt"

// 2. 日期补零与格式化场景(例如提取年份后两位或双位月份)
const dateStr = "2026-11-03";
const day = dateStr.slice(-2);
console.log(day); // 输出: "03"

// 3. 数值补齐双位数截取
const num = "7";
const padded = ("0" + num).slice(-2);
console.log(padded); // 输出: "07"

slice() 方法执行时不会修改原始字符串(JavaScript 中的字符串均为不可变原始值),而是返回包含目标字符的新字符串。

JS怎么截取字符串最后两位
图 1:str.slice(-2) 核心调用与截取执行流程

二、底层原理解析:负数索引是如何生效的?

为什么传入 -2 就能精准锁定最后两位字符?这源于 ECMAScript 规范对 String.prototype.slice(beginIndex, endIndex) 参数的标准化定义。

在 JavaScript 中,字符串每个字符都具备两套定位坐标:

  • 正向索引(从头开始):从 0 依次递增到 length - 1。
  • 反向负索引(从尾开始):最后一个字符固定为 -1,倒数第二位为 -2,倒数第 k 位即为 -k。

当 slice(beginIndex) 的起始参数为负数时,其内部等价于执行了如下换算:

// 引擎内部换算逻辑伪代码
let fromIndex = beginIndex < 0 ? Math.max(str.length + beginIndex, 0) : beginIndex;

例如,若字符串长度为 10,传入 -2 经过计算后为 10 + (-2) = 8。因为没有传递第二个截取终点参数 endIndex,函数默认从索引 8 一直截取到串尾索引 10(左闭右开区间 [8, 10)),正好取得最后两个字符(即索引 8 和 9 处的字符)。

JS怎么截取字符串最后两位
图 2:字符串正向索引与负向索引映射关系及截取范围

三、常见替代方案与对比说明

除了 slice(-2),部分开发者还会联想到 substring 或 substr。我们必须清楚它们各自的差异与潜在缺陷,避免在实际项目中埋下隐患。

1. str.substring(str.length - 2)

substring 是早期 JavaScript 标准中常用的截取手段。但它有一个致命差异:不支持负数索引。如果在 substring 中直接传入负数,它会默认将负数当作 0 处理(即 str.substring(-2) 等价于 str.substring(0),会直接返回整个完整字符串)。

因此若使用 substring 提取最后两位,必须显式计算字符串长度:

const text = "Frontend";
const res = text.substring(text.length - 2);
console.log(res); // 输出: "nd"

该写法完全可行,但相比 slice(-2) 多写了 text.length -,在代码复用与阅读体验上较为繁琐。

2. str.substr(-2)(已废弃,不推荐)

规范预警:String.prototype.substr() 已被 ECMAScript 官方规范正式列入 附录 B(Annex B - 仅用于向后兼容的遗留特性),并在 MDN 文档中被标记为 Deprecated。

尽管现代浏览器和 Node.js 运行时为了兼容旧网页仍然保留了 substr,且部分支持负数起始值,但严禁在现代前端或 Node.js 项目中使用该 API,以防在打包工具或严格模式兼容性检测时出现告警或非预期错误。

3. ES2022 的新特性:str.at(-2) + str.at(-1)

在较新的 ECMAScript 2022 规范中,引入了 at() 方法,原生支持负索引单独获取单个字符。如果只需要获取特定的某一个末尾字符,str.at(-2) 是首选;若要获取两位,虽然可以拼合,但依然不如 slice(-2) 直观高效:

const word = "React";
console.log(word.at(-2)); // 输出: "c" (倒数第二位单字符)
console.log(word.at(-1)); // 输出: "t" (最后一位单字符)
JS怎么截取字符串最后两位
图 3:截取末尾两位常见方案对比矩阵

四、边界情况与防御式处理

在实际生产业务中,输入数据往往不可完全信任。为了保证程序高健壮性、不抛出未捕获的 Uncaught TypeError,我们需要针对各种边界场景进行防御:

1. 字符串长度小于 2 或为空串

当原字符串长度本身只有 1 个字符或为空串 "" 时,str.slice(-2) 的表现非常安全:

  • 对于空串 "".slice(-2),结果为 "";
  • 对于单字符 "A".slice(-2),计算时 1 + (-2) = -1,经 Math.max(-1, 0) 换算后实际从索引 0 截取到末尾,直接返回 "A"。

这说明 slice(-2) 不会发生数组越界崩溃,天然具备容错能力。

2. 输入参数为 null、undefined 或非字符串类型

如果传入的值不是 string(如 null、undefined 或数值),直接调用 .slice() 会抛出 TypeError: Cannot read properties of undefined。因此需在函数入口前进行类型校验或转换:

// 防御式类型转换
function safeGetLastTwo(val) {
  if (typeof val !== "string") {
    if (val === null || val === undefined) return "";
    val = String(val); // 转为字符串
  }
  return val.slice(-2);
}

3. 特殊字符:包含 Emoji 表情或生僻字(代理对)

JavaScript 内部采用 UTF-16 编码单元,绝大多数 Emoji(如 🚀、🎉)以及部分生僻字在内部由 2 个代理对单元(Surrogate Pair)构成。若字符串末尾恰好包含此类字符,简单的 slice(-2) 可能会截断字符编码,导致乱码显示(如出现 \uD83D 乱码):

const strWithEmoji = "前端🚀";
console.log(strWithEmoji.length); // 长度为 4("前" 1位,"端" 1位,"🚀" 占2个编码单元)

// 普通 slice(-2) 截取的实际上是 Emoji 的双字节单元
console.log(strWithEmoji.slice(-2)); // 输出: "🚀" (仅为一个复合表情,非两个独立字符)

若需求是严格按字素/视见符号(Grapheme / Code Point)截取最后两个独立符号,应先借助 ES6 扩展运算符 [...str] 或 Array.from(str) 展开码点:

const textEmoji = "学习JS🚀🎉";
const lastTwoGraphemes = [...textEmoji].slice(-2).join("");
console.log(lastTwoGraphemes); // 正确输出: "🚀🎉"
JS怎么截取字符串最后两位
图 4:生产环境边界防御与安全截取决策树

五、生产级函数封装与实战速查

综合上述原理与异常保护,我们可以在通用工具库(如 stringUtils.js)中封装一个生产高可用截取函数:

/**
 * 安全截取字符串最后两位字符
 * @param {any} input - 待截取的目标输入
 * @param {boolean} [isUnicode=false] - 是否启用 Unicode 码点解构(应对 Emoji)
 * @returns {string} 截取后的结果
 */
function getLastTwoChars(input, isUnicode = false) {
  if (input === null || input === undefined) {
    return "";
  }
  
  const text = typeof input === "string" ? input : String(input);
  
  if (text.length <= 2 && !isUnicode) {
    return text;
  }
  
  if (isUnicode) {
    const charArr = [...text];
    return charArr.slice(-2).join("");
  }
  
  return text.slice(-2);
}

// 验证测试用例
console.log(getLastTwoChars("Hello World"));   // "ld"
console.log(getLastTwoChars("A"));             // "A"
console.log(getLastTwoChars(""));              // ""
console.log(getLastTwoChars(12345));          // "45"
console.log(getLastTwoChars(null));           // ""
console.log(getLastTwoChars("苹果🍎西瓜🍉", true)); // "西瓜🍉" 对应字符

方法速查表

截取方式 示例代码 负索引支持 推荐指数 核心适用场景
str.slice(-2) str.slice(-2) 原生支持 ★★★★★ 绝大多数业务场景的首选,最简语法
str.substring str.substring(str.length - 2) 不支持负数 ★★★☆☆ 仅在必须兼容古老规范或约束时使用
Array.from + slice [...str].slice(-2).join('') 原生支持 ★★★★☆ 输入中包含 Emoji、符号或代理对字符时
str.substr str.substr(-2) 规范已弃用 ★☆☆☆☆ 禁止在现代代码库中使用
总结:日常业务记住 str.slice(-2) 这一行代码即可解决 99% 的截取字符串末尾两位需求;在封装公共库时,搭配类型兜底与 Unicode 解构即可做到万无一失。
作者最新文章
相关文章
更多