前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库TextEncoder 字符串转UTF-8 Uint8Array
JavaScript数据处理

TextEncoder 为什么只能输出 UTF-8,能指定成 GBK 吗?

TextEncoder 的规范就规定了只输出 UTF-8,encoding 属性永远是 utf-8,构造函数传 gbk 也会被忽略。要生成 GBK 之类的字节,只能用第三方库或者交给服务端转换。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数据处理
先看核心答案读代码示例
理解线索

字符串到 UTF-8 字节的换算

  1. length字符串的 UTF-16 单元数,emoji 算 2
  2. byteLength编码后的 UTF-8 字节数,汉字算 3,emoji 算 4
  3. encodeInto往调用方给的数组里写,空间不够就只写完整的前缀

编码和解码不对称。TextDecoder 能解 GBK、Big5、UTF-16 等很多编码,TextEncoder 却只有 UTF-8,因为 Web 平台希望新产生的数据统一用 UTF-8。

核心回答

先记住这个答案

因为规范就这么定的。WHATWG 的 Encoding 标准里,TextEncoder 只支持 UTF-8,构造函数没有编码参数,它的 encoding 属性永远返回 'utf-8'。早期规范曾允许传编码名,后来删掉了,原因是 Web 平台希望新产生的数据都用 UTF-8,不再鼓励生成老编码。所以 new TextEncoder('gbk') 不会报错,但参数被直接忽略,输出还是 UTF-8。要生成 GBK 字节只能靠第三方库或者服务端。

  • TextEncoder 只输出 UTF-8,传参也改不了
  • ASCII 占 1 字节,常用汉字 3 字节,emoji 4 字节
  • 字节数要看 byteLength,不能看字符串 length
  • encodeInto 写进已有数组,返回 read 和 written

一个字符会变成几个字节

UTF-8 是变长编码:ASCII 字符 1 个字节,常用汉字 3 个字节,emoji 4 个字节。这决定了字符串长度和字节数经常对不上。

encode 的结果JavaScript
const encoder = new TextEncoder()
console.log(encoder.encoding) // 'utf-8',固定值

const bytes = encoder.encode('A你😀')
console.log([...bytes])
// [65, 228, 189, 160, 240, 159, 152, 128]
// A 占 1 个,你 占 3 个,😀 占 4 个

console.log('A你😀'.length)  // 4,😀 在 UTF-16 里是 2 个单元
console.log(bytes.byteLength) // 8,真正的字节数

同一个字符串,length 是 4,字节数是 8。length 数的是 UTF-16 单元(JavaScript 字符串内部的存储单位),和 UTF-8 字节没有关系。 这在实际开发里很常见:后端数据库字段限制 255 字节,前端按 length 限制 255 个字符,用户输入全是中文时实际有 765 字节,入库直接失败。算字节数的正确写法是 new TextEncoder().encode(text).byteLength。

encode 和 encodeInto 怎么选

encode 每次返回一个新的 Uint8Array,简单直接,大多数场景用它就行。encodeInto 是往一个你已经准备好的数组里写,不分配新内存,适合高频循环或者往 WebAssembly 的内存里写字符串。

空间不够时 encodeInto 怎么处理
encodeInto(text, target) 返回一个对象 { read, written }。read 是读了多少个 UTF-16 单元,written 是写了多少字节。比如目标数组只有 4 个字节,写 'A你好':A 占 1 字节,「你」占 3 字节,刚好写满;「好」放不下,它不会写半个进去,而是停下。返回 { read: 2, written: 4 },调用方看到 read 小于字符串长度,就知道还有剩余,从第 2 个单元继续写。 这里之所以要两个数字,是因为输入按 UTF-16 单元计、输出按字节计,两者的比例不固定,只给一个数没法知道下次从哪继续。
回答前,多想一步

容易答错的地方

以为传参能指定编码
new TextEncoder('gbk') 不报错,看起来像生效了,实际输出还是 UTF-8。要是拿这个结果去对接只认 GBK 的老系统,中文全是乱码。
用 length 给 encodeInto 预分配空间
new Uint8Array(text.length) 对中文字符串是不够的。安全的上限是 text.length * 3:一个 UTF-16 单元最多编码成 3 个字节,emoji 虽然是 4 字节,但它本身占 2 个单元,也在这个上限内。
以为 TextEncoder 会保留所有字符串原样
JavaScript 字符串里可能有孤立的代理项,比如把 emoji 从中间截断留下的半个。它不是合法的 Unicode 字符,TextEncoder 会把它换成替换字符 U+FFFD,编码成 EF BF BD 三个字节。原来的半个 emoji 就这样丢了,而且不报错。
试着用自己的话回答

面试官还会怎么问?

怎么把 UTF-8 字节转回字符串?

用 new TextDecoder().decode(bytes)。解码器默认也是 UTF-8,和编码器正好是一对。如果字节是分块到达的,要传 { stream: true } 防止一个字被切成两半。

以前没有 TextEncoder 时怎么算字节数?

老写法是 unescape(encodeURIComponent(str)).length,利用 encodeURIComponent 按 UTF-8 转成百分号编码,再还原成每个字节一个字符。unescape 已经被标记为废弃,现在直接用 TextEncoder,或者用 new Blob([str]).size。

为什么 TextDecoder 能解 GBK,TextEncoder 却不能编 GBK?

解码要面对已经存在的大量老数据,老网页、老文件都是 GBK、Big5,浏览器必须能读。编码是产生新数据,规范的立场是新数据一律用 UTF-8,所以只保留了 UTF-8。这是有意的设计,不是遗漏。

从一道题,走向一组知识

把知识连起来

数据处理

Uint8Array 和普通数组有什么区别?

encode() 返回的就是 Uint8Array,理解它和普通数组的区别,才知道结果为什么不能 push。

数据处理

类型化数组的 subarray 和 slice 有什么区别?

encodeInto 之后常用 subarray(0, written) 取出有效字节,这里要分清共享视图和复制。

参考资料

  • JavaScript:数据处理参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 一个字符会变成几个字节
  3. encode 和 encodeInto 怎么选
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑