const viewPerOneByte = new Uint8Array(buf) //在buf上建立一个以单个字节为单位操作的view
viewPerOneByte[0] = 65
viewPerOneByte[1] = 66
// 此时两块内存的值分别为
// 0100 0001 (41H)
// 0100 0002 (42H)
问题来了!
参考: https://hacks.mozilla.org/2017/01/typedarray-or-dataview-understanding-byte-order/
既然这个buf是两个字节,那其实也可以用Uint16Array来直接进行操作吧?
const viewPerTwoBytes = new Uint16Array(buf)
viewPerTwoBytes[0] = (65 << 8) + 66
//没毛病,等同于4142H
但实际上此时的存储顺序为
console.log(viewPerOneByte[0]) //输出66 (42H)
console.log(viewPerOneByte[1]) //输出65 (41H)
可以看到存储的顺序颠倒了。
明明是一样的值,但是为什么呢?
(p.s. 内存以字节为单位)
简单的说,当存储超过大小为两个字节及以上的值时,就会出现字节序(端序)问题(Endianness)。
字节序可分为大端序(Big-Endian)以及小端序(Little-Endian),具体定义请看端序。简单来说,大端序即按照人正常的阅读顺序来存储值为多个字节的每个字节,小端序则反过来存。
为什么要这么分?
大端序:主要用在网络传输。在接收文件流(stream)时很方便,接收到的包只需直接放接收队列最后。
小端序:主要用在各大操作系统。有性能上的提高,比如同一个地址即使按照不同的量度(1字节,2字节等)来读也能得到同一个值。
例如用两字节来存16
小端序下为
0001 0000 | 内存地址0xff00
0000 0000 | 内存地址0xff01
内存指针指向0xff00
以两个字节为单位(例如数据类型short)来读,可得到值16
以一个字节为单位(例如数据类型char)来读,也可得到16
-----------------
但如果按照大端序来存
则用一个字节为单位来读时,需要将内存指针右移。
TypedArray按照操作系统的端序来存多字节值(基本可以假设为小端序)
DataView
如不指定,DataView默认按照大端序来存多字节值。
UTF-8与UTF-16
像UTF-16这些编码实现方式需要在文件头指定其端序,但UTF-8的介绍里说它不需要端序。
原因就是UTF-16用两个字节形容字符并将其这两个字节作为一个元素来存储。
而UTF-8则以单个字节为元素来存储字符。至于变长相关的具体解码可以参考https://stackoverflow.com/questions/1543613/how-does-utf-8-variable-width-encoding-work
比如以’好’这个U+597D字符为例,注意它的UTF-8编码方式的不同:
查找中日韩字符的Unicode