JavaScript Unicode 编码与解码:转义序列、码点与 Emoji 处理
· 阅读需 2 分钟
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 参数应使用 encodeURIComponent 和 decodeURIComponent:
const urlValue = encodeURIComponent("中文");
console.log(urlValue);
console.log(decodeURIComponent(urlValue));
不要使用 Unicode 转义函数代替 URL 编码,也不要对不可信字符串直接使用 eval 进行解码。