去提问»
提问背景 Question:
还有这 if (typeof htmlString !== "string") { return htmlString; } 我以前没发现

JS防御性编程:为何HTML转义函数需要类型检查

发布时间:2026-08-19 16:50 👁️ 阅读:1

为什么需要 typeof htmlString !== "string" 类型检查?

这是一个非常典型且优秀的**防御性编程(Defensive Programming)**实践。在 JavaScript 这种弱类型/动态类型语言中,这个判断至关重要,主要有以下几个原因:

1. 防止程序崩溃(运行时错误)

JavaScript 的 .replace() 方法是 String 实例上的方法。如果传入的参数不是字符串(例如 undefined, null, number, object 等),直接调用 .replace() 会立即抛出 TypeError

// 如果没有类型检查:
escapeHtml(undefined); // 报错:Uncaught TypeError: Cannot read properties of undefined (reading 'replace')

一旦抛出未捕获的异常,可能会导致整个前端页面卡死,或者 Node.js 异步任务中断。加上这行代码后,即使传入了非预期类型,函数也能安全退出,不会使程序崩溃。

2. 应对不确定的后端或用户输入

在实际开发中,数据往往来自后端 API 或用户输入,我们无法100%保证拿到的字段一定是字符串:

  • 接口字段可能因为数据库缺失而返回 null 或直接是 undefined
  • 原本应该是 HTML 字符串的字段,在某些异常情况下可能返回了数字(如错误码 500)或对象。
  • 通过类型守卫,可以让这个公共工具函数具备极强的容错性。

更好的健壮性写法建议

虽然原样返回 htmlString 已经能防止崩溃,但在实际业务中,我们还可以根据需求进一步优化:

方案 A:安全强制转换(适合需要展示非字符串数据的场景)

如果你希望数字 123 也能被安全转义并以字符串 "123" 输出,而不是原样返回数字类型,可以先进行安全转换:

function escapeHtml(val) {
  // 1. 如果是 null 或 undefined,返回空字符串,避免显示 "null" 字样
  if (val === null || val === undefined) {
    return "";
  }
  
  // 2. 强制转换为字符串类型(这样数字、布尔值也能安全转义)
  const str = String(val);

  return str
    .replace(/&/g, "&")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

方案 B:配合 TypeScript 进行双重保障

如果你在项目中使用 TypeScript,可以通过类型约束在编译阶段就拦截大部分错误,并配合运行时的防御性代码:

function escapeHtml(htmlString: string): string {
  if (typeof htmlString !== "string") {
    return ""; // 运行时防御性兜底
  }
  return htmlString
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

总结:
编写公共工具函数(Utility Functions)时,**“永远不要相信用户的输入”“永远不要相信接口的数据格式”**是核心原则。加上类型校验,是区分“能跑的代码”和“企业级健壮代码”的重要分水岭。