【问题标题】:If <meta charset=“utf-8”> means that JavaScript is using utf-8 encoding instead of utf-16如果 <meta charset="utf-8"> 表示 JavaScript 使用的是 utf-8 编码而不是 utf-16
【发布时间】:2018-12-31 10:46:07
【问题描述】:

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

Let’s talk about Javascript string encoding

所以我假设这就是存在诸如 utf8.js 之类的库以在 UTF-16 和 UTF-8 之间转换的原因。

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

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

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

这让我想起了 HTML 中的 &lt;meta charset=“utf-8”&gt; &lt;head&gt;,除了“你需要这个来让文本正常工作”之外,我从来没有真正想过太多。

现在我想知道,这个问题是关于哪个&lt;meta charset=“utf-8”&gt; 标签告诉JavaScript 进行UTF-8 编码。这意味着当您在 JavaScript 中创建字符串时,它们将是 UTF-8 编码而不是 UTF-16。或者如果我错了,它到底在做什么。如果它告诉 JavaScript 使用 UTF-8 编码而不是 UTF-16(我猜这将被视为“默认”),那么这意味着您不需要为在UTF-8 和 UTF-16,这意味着性能提升。想知道我是否理解正确,或者如果没有,我错过了什么。

【问题讨论】:

标签: javascript html encoding utf-8 character-encoding


【解决方案1】:

JavaScript 使用 UTF-16

HTML5 使用 UTF-8

&lt;meta charset=“utf-8”&gt; 设置适用于 HTML5 网页编码,这是可选的,因为大多数现代浏览器都知道 HTML5 是从 UTF-8 编码和解码的。 此元标记设置与 JavaScript 编码无关,但是,它不会更改或影响 JavaScript,只是告诉它使用 UTF-8 编码解码您的页面,这在所有较新的浏览器中都会执行默认情况下。

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

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

<meta http-equiv="Content-Script-Type" content="text/javascript; charset=UTF-8;">

JAVASCRIPT 引擎的工作原理

大多数现代 JavaScript UTF-16 解码引擎的工作方式是是的,它们会读取 Web 文件、脚本文件、HTML 标记和页面文本并将其解码为 UTF-16。如今,其中大多数默认情况下以 UTF-8 或 ASCII 形式存储。但是出于速度和其他原因,JavaScript 通常以原生形式存储第一个 ASCII 集(英文字符和数字),或者像 UTF-8 一样作为一个字节存储,或者使用与 HTML5 网页默认使用的编码相同的编码。这不是一个硬性规定。因此,在 Chrome 的 V8 JavaScript 引擎中由 JavaScript 读取和存储的 HTML 标签可能仍将它们存储在 1 字节 UTF-8 中,而不是 2 字节 UTF-16 中。

这些脚本引擎在 UTF-8 编码或 ASCII 方面发生了什么,以及它们如何存储在内存中,您不必担心。只有在流式传输更复杂的 Unicode 字符上“平面”时才会遇到问题。 Javascript存储和编码的UTF-16特性是可变的,我读过。在我看来,在您进入高级 Unicode 语言和 Javascript 中的字符集操作之前,大多数 Web 开发人员都不需要担心它。这就是 Node 和许多开源引擎在解码和编码 UTF-8 和 UTF-16 方面遇到的困难,因为它们依赖于 Javascripting 引擎。

再一次,因为现在一切都在朝着 UTF-8 编码发展(其中 1-4 字节可选地用于编码完整的 Unicode 字符集,而 UTF-16 以 2 字节集开始并上升)你会看到 Javascript处理所有将 UTF-8 解码为 UTF-16 的过程,然后作为一个非常无缝的过程退出,并有很多应急措施。

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

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

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

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

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

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

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

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

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

【讨论】:

    【解决方案2】:

    元字符集

    &lt;meta charset=“utf-8”&gt; 标签告诉 HTML(不那么草率:HTML 解析器)页面的编码是 utf8。

    JS 没有在不同的字符串编码之间切换的内置工具 - 它始终是 utf-16。

    渐近界

    我认为编码转换不会有O(n) 的惩罚。每当这种编码更改到期时,已经有 一个O(n) 操作:读/写数据流。所以每个八位字节上的任何固定数量的操作仍然是O(n)。编码变化只需要本地知识,即。仅固定长度的前瞻窗口,因此可以合并到流读/写代码中,惩罚为O(1)

    您可能会争辩说空间损失是O(n),但如果需要以任何标准编码(即不压缩)存储字符串,则移动到 utf-16 意味着最大因子为 2,因此保持在O(n) 范围内。

    常数因子

    即使关注的是最小化隐藏在O(n) 符号编码更改中的常数因素,至少在时域中也会产生适度的影响。对于大部分(西方)文本数据,将 utf-16 流作为 utf-8 写入/读取意味着每隔一个八位字节跳过/插入空八位字节。与与套接字或文件系统接口产生的开销和延迟相比,这种性能损失相形见绌。

    当然,存储是不同的,尽管今天的存储相对便宜,而且 2 的上限仍然成立。从 32 位迁移到 64 位对数字表示和指针的记忆影响更大。

    【讨论】:

      猜你喜欢
      • 2020-10-26
      • 1970-01-01
      • 2015-08-21
      • 2019-07-31
      • 2011-12-13
      • 2011-06-09
      • 2014-11-02
      • 2015-12-07
      相关资源
      最近更新 更多