相关文章推荐

ArrayBuffer与TypedArray

什么是ArrayBuffer?简单来说,就是按照你的需求n来为你划分出n字节大小的内存区域,称其为Buffer。

const buf = new ArrayBuffer(2)  //划分出2字节大小的内存(即16bit)

但不能对这个buf直接进行读写操作,可以通过 TypedArray DataView 来对它整块整块(按照一定的字节数)地操作。按照“整块具体是多少字节”以及“数字是否有符号”, TypedArray 分为 Int8Array , Uint8Array , Uint16Array , Uint32Array 等等

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

 
推荐文章