跳到主要内容

JavaScript Unicode 编码与解码:转义序列、码点与 Emoji 处理

· 阅读需 2 分钟
Apache王也道长
软件开发者与技术作者

JavaScript 字符串内部使用 UTF-16 编码。开发中常见的 \\u4e2d\\u6587 属于 Unicode 转义序列,可用于在纯 ASCII 文本中表示中文等字符。

基础编码与解码

原始实现如下,适合基本多文种平面中的常见字符:

function encodeUnicode(str) {
const result = [];

for (let i = 0; i < str.length; i++) {
result.push(
"\\u" + str.charCodeAt(i).toString(16).padStart(4, "0")
);
}

return result.join("");
}

function decodeUnicode(str) {
return str.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) =>
String.fromCharCode(parseInt(hex, 16))
);
}

const encoded = encodeUnicode("中文");
console.log(encoded); // \\u4e2d\\u6587
console.log(decodeUnicode(encoded)); // 中文

相比使用已不推荐的 unescape,通过正则表达式配合 String.fromCharCode 更直观,也不会把普通百分号编码混入处理流程。

为什么 Emoji 会变成两个转义序列

charCodeAt 每次读取一个 UTF-16 代码单元。Emoji 等字符可能由一对代理项组成,因此会编码成两个 \\uXXXX

console.log(encodeUnicode("😀"));
// \\ud83d\\ude00

这仍然可以被前面的 decodeUnicode 正确还原。

按 Unicode 码点编码

如果希望把 Emoji 表示为 \\u{1f600},可以按码点遍历:

function encodeCodePoints(str) {
return Array.from(str, char => {
const codePoint = char.codePointAt(0);
return codePoint <= 0xffff
? "\\u" + codePoint.toString(16).padStart(4, "0")
: "\\u{" + codePoint.toString(16) + "}";
}).join("");
}

function decodeCodePoints(str) {
return str
.replace(/\\u\{([0-9a-fA-F]+)\}/g, (_, hex) =>
String.fromCodePoint(parseInt(hex, 16))
)
.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) =>
String.fromCharCode(parseInt(hex, 16))
);
}

const value = encodeCodePoints("中文😀");
console.log(value); // \\u4e2d\\u6587\\u{1f600}
console.log(decodeCodePoints(value)); // 中文😀

Unicode 转义与 URL 编码的区别

两者用途不同:

  • Unicode 转义:中文\\u4e2d\\u6587
  • URL 编码:中文%E4%B8%AD%E6%96%87

URL 参数应使用 encodeURIComponentdecodeURIComponent

const urlValue = encodeURIComponent("中文");
console.log(urlValue);
console.log(decodeURIComponent(urlValue));

不要使用 Unicode 转义函数代替 URL 编码,也不要对不可信字符串直接使用 eval 进行解码。

本文阅读量:--

总访问量 -- · 访客数 --