如果 <meta charset=“utf-8”> 表示 JavaScript 使用 utf-8 编码而不是 utf-16

Lan*_*ard 3 html javascript encoding utf-8 character-encoding

我一直试图理解为什么 JavaScript 领域中到处都需要对 UTF-8 进行编码/解码,并了解到 JavaScript 使用 UTF-16 编码。

\n\n

让\xe2\x80\x99s谈谈Javascript字符串编码

\n\n

所以我假设这就是utf8.js等库存在的原因,用于在 UTF-16 和 UTF-8 之间进行转换。

\n\n

但最后他提供了一些见解:

\n\n
\n

Node 中的编码非常混乱,而且很难正确执行。不过,当您意识到 Javascript 字符串类型始终被编码为 UTF-16,并且 RAM 中的大多数其他位置的字符串与套接字、文件或字节数组交互时,该字符串会被重新编码为 UTF-8,这会有所帮助。 。

\n\n

当然,这一切都是非常低效的。大多数字符串都可以表示为 UTF-8,并且使用两个字节来表示其字符意味着您使用的内存超出了您的需要,并且每次遇到 HTTP 时都要支付 O(n) 税来重新编码字符串或文件系统边界。

\n
\n\n

这让我想起了<meta charset=\xe2\x80\x9cutf-8\xe2\x80\x9d>HTML 中的<head>,除了“你需要这个才能使文本正常工作”之外,我从未真正考虑过太多。

\n\n

现在我想知道这个问题是关于哪个<meta charset=\xe2\x80\x9cutf-8\xe2\x80\x9d>标签告诉JavaScript进行 UTF-8 编码的。这意味着当您在 JavaScript 中创建字符串时,它们将采用 UTF-8 编码,而不是 UTF-16。或者如果我错了,它到底在做什么。如果它告诉 JavaScript 使用 UTF-8 编码而不是 UTF-16(我猜这将被视为“默认”),那么这意味着您不需要为O(n)UTF-16 之间的转换支付税费。 8 和 UTF-16,这意味着性能的提高。想知道我是否理解正确,或者如果不正确,我错过了什么。

\n

Sto*_*ely 7

首先,要知道在大多数网络浏览器中,无论过去还是现在......

\n

JavaScript 引擎使用UTF-16

\n

浏览器 HTML5 解析器使用UTF-8

\n
\n

其次,下面的这个元标记不是必需的,但推荐......

\n
<meta charset=\xe2\x80\x9cutf-8\xe2\x80\x9d />\n
Run Code Online (Sandbox Code Playgroud)\n

设置此元标记会影响您的 HTML/HTML5 网页编码,这是可选的,因为大多数现代浏览器都知道 HTML/HTML5 是从 UTF-8 编码和解码的。顺便说一句,现在大多数网络都是 HTML5,UTF-8 是默认编码。

\n

HTML 3 或 4 系列浏览器中较旧的编码/解码系统对大多数说英语的人使用各种风格的 ASCII,其存储方式与 UTF-8 使用的方式相同。因此,无论过去还是现在,大多数网络浏览器都是交叉兼容的,无需任何元标记设置或额外的编码/解码例程。

\n

但是,此元标记设置与 JavaScript 编码无关,并且不会更改或影响 JavaScript,除了告诉它使用 UTF-8 编码对页面进行解码(默认情况下,它在所有较新的浏览器中都会这样做)。但是这个元标记会告诉 Web 浏览器的 JavaScript 引擎应该对网页进行编码,以及如何将其解码为 JavaScript 在解析和操作网页 DOM 时存储字符编码的 UTF-16。

\n

有一个已弃用的元标记是可选的,允许您控制外部或内部<script>脚本和文件的编码方式。但这不再受 HTML5 支持,也不会改变 JavaScript 引擎自然解码这些文件的方式。

\n

这个旧的元标记如下所示,但不应使用

\n
<meta http-equiv="Content-Script-Type" content="text/javascript; charset=UTF-8;" />\n
Run Code Online (Sandbox Code Playgroud)\n
\n

JavaScript 引擎如何工作

\n

大多数现代 JavaScript UTF-16 解码引擎的工作方式是,它们确实读取 Web 文件、脚本文件、HTML 标记和页面文本,并将其从 UTF-8 或 ASCII 直接解码为内存中的 UTF-16。

\n

这意味着当他们读取基本的英语或 ASCII 字符和数字时,他们会将它们存储为两个字节,而他们通常不仅需要一个字节来阅读大多数基于英语的网站。然而,这种 UTF-16 功能允许 JavaScript 还存储任何可能出现在 2-4 字节范围内的较大平面 Unicode 字形和字符以及较低平面英语 ASCII 字形和字符。

\n

到 2022 年,网页、脚本文件和 Web 上的外部文本中的大多数字符默认存储为 UTF-8(或在某些情况下存储为 ASCII,即旧模型)。UTF-8 和 UTF-16 都支持当今存在的全部 Unicode 字符(超过一百万个代码点),并且工作原理相同,除了存储编码字符的方式不同。这主要影响 Unicode 上层平面的编码和解码,这些平面是内存中非常大的整数。

\n

大多数 UTF-8 和 ASCII 都可以安全地存储在 1 个字节中,因此 UTF-8 是当今的默认值,并且与新旧网页编码和解码交叉兼容。这就是为什么 HTML5 是 UTF-8 并且运行良好的原因。但 JavaScript 很早就计划解决高阶 Unicode 语言和字形的问题。因此,他们决定以 UTF-16 存储所有内容,并保留更多内存块来处理更高平面 Unicode 字符的更大存储。

\n

但出于速度和其他原因,JavaScript 仍然经常以其本机形式存储第一个 ASCII 集(英文字符和数字),或者作为 UTF-8 中的一个字节存储在内存中,或者使用与 HTML5 网页默认使用的相同编码。这不是一个硬性规定。因此,Chrome 的 V8 JavaScript 引擎中的 JavaScript 读取和存储的 HTML 标签可能仍以 1 字节 UTF-8 存储,而不是 2 字节 UTF-16。这是您不需要 HTML 来告诉 JavaScript 如何编码或解码网页或脚本文件的又一个原因。引擎会为您处理所有这些事情,并且许多引擎最终都会以 UTF-8 本机方式存储内容以提高速度。同样,当您开始使用外来语言、字形、字体集和表情符号时,非常大的代码点数字需要更多内存,如果在服务器上或发送到浏览器的文件中未正确编码和解码,则可能会导致问题解释。

\n

您无需担心这些脚本引擎在 UTF-8 编码或 ASCII 方面所发生的情况以及它们如何存储在内存中。仅当流式传输更复杂的 Unicode 字符上部“平面”时,您才会遇到问题。Javascript存储和编码的UTF-16特性是可变的,我已经阅读过。在我看来,这并不是大多数 Web 开发人员需要担心的事情,除非您进入了上层 Unicode 语言和 Javascript 中的字符集操作。这就是 Node 和许多开源引擎在解码和编码 UTF-8 和 UTF-16 方面遇到的困难,因为它们依赖于 JavaScript 引擎。

\n

再次强调,因为现在一切都在朝着 UTF-8 编码方向发展(其中 1-4 字节可选地用于编码完整的 Unicode 字符集,而 UTF-16 则从 2 字节集开始并不断增加),您将看到 Javascript 处理所有这些将 UTF-8 解码为 UTF-16 并返回是一个非常无缝的过程,并且存在很多意外情况。

\n

顺便说一句......脚本引擎将大多数 HTML5 网页读取为 UTF-8,包括它们自己的外部 JavaScript 页面。然后,他们将其翻译或“编码”回内存中的 UTF-16。然而,如上所述,由于 ASCII 英文字符占大多数字符的 99%,并且在 UTF-8 和 UTF-16 的内存中读取和存储相同的字符,因此这些引擎很少尝试将它们存储在 UTF-16 中。这是浪费内存。但 JavaScript 还必须从服务器解析和存储其自己的外部 Javascript Web 文件,这些文件通常也以 UTF-8(默认)或 ASCII 编码,而不是 UTF-16。默认情况下,大多数浏览器在没有额外的字符集指令的情况下,都会遵循 Web 服务器的“内容类型”并假设它们全部采用 UTF-8 或 ASCII,很少采用 UTF-16。大多数开发人员在几乎所有情况下都会不知不觉地将 JavaScript 保存为 UTF-8,这工作得很好。

\n

但是 JavaScript 必须将这些字符从 UTF-8“解码”为 UTF-16 以供其内部使用,尤其是当您的脚本内部包含上层 Unicode 字符时。

\n

如前所述,对于这些库中编码的大多数脚本字符来说,很少需要它,除非在文件中找到一些非常大的上平面 Unicode。如果您选择使用具有大量复杂 Unicode 的脚本文件来帮助 JavaScript 浏览器引擎,那么在这种情况下,您可能会考虑将脚本文件编码为 UTF-16,然后使用元标记设置您的服务器或 HTML5,以指示脚本引擎尝试并执行以下操作:将外部脚本文件解码为 UTF-16。

\n

这是唯一可能至关重要的情况。JavaScript 浏览器引擎将侦听来自服务器的 HTTP 标头中的 mime 类型或“内容类型”和字符集,以了解所有网页文件应在 HTML 元标记之前首先解码。如前所述,现在 HTML5 中几乎总是 UTF-8。如果它无法从 HTTP 服务器标头确定类型,它接下来会检查您的 HTML5 网页和脚本的<script>标记及其自定义类型属性的 MIME 类型和/或字符集,以查看您的 JavaScript 源文件是否已设置该编码类型。如果您已使用 UTF-16 编码这些文件,则可以将其设置为 UTF-16。否则,它假设 UTF-8 或 ASCII 的工作原理与将字符从位基本编码为数字相同。在大多数情况下,网站中缺少这些设置,这也没关系,现代脚本引擎有很多后备检查并假定 UTF-8。

\n

如果 JavaScript 引擎出现问题,它将检查 HTML5 页面的网页元标记“字符集”,它要么是 UTF-8,要么如果使用 HTML5,则假定为 UTF-8。对于脚本,如果您已以这种方式对这些页面进行编码(这并不常见),则可以将该元标记设置为 UTF-16。

\n

最后,脚本文件上还有“字节顺序标记”或 BOM,可能是 UTF-8。Microsoft 产品因在文件中添加 BOM 而臭名昭著,这在某些情况下可能会导致问题。这是他们在文件头的前几个字节中自行分配文件编码的一种方法,这比尝试解析和嗅探完整文件要快得多。但有时它会导致浏览器出现问题。

\n

即使您的 Web 文件(例如 HTML 和 JavaScript)采用 ASCII 或 Latin-1 编码,无论如何,它仍然会直接转换为 UTF-8。只有旧 Windows 机器上的 ANSI 具有某些无法交叉转换回 Unicode 的字符的 Unicode 编号。这就是为什么您偶尔会在网页中看到无法识别的乱码。其中大部分是无法从 ANSI 编码映射到 UTF 编码的高级字符,因此会丢失。

\n

但是,一旦 JavaScript 浏览器引擎知道所有 Web 文件的编码类型,它就可以解码这些位并提取字符数,并将它们重新编码到自己的 2 字节 UTF-16 内存集中,如上所述。

\n

这里的其他一些发帖者正在争论解析、内存或存储速度和空间节省,但这是一个没有实际意义的问题,因为这些脚本引擎已经完善了 20 多年,并且旨在实现效率最大化。

\n

归根结底,引擎会很好地为您解决所有这些问题:)

\n