JavaScript 在 ES6 引入那些集合类型—TypeArray(2)

285 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

Typed Array API 中存在两个对象

Buffers

ArrayBuffer 的实例用于持有二进制数据

Views

提供访问二进制数据的方式,主要有两种视图

  • Typed Array 的构造函数的实例(Uint8Array、Float64Array等)的工作方式与普通数组很相似,但需要其元素的类型需要一致,并且没有空穴。
  • DataView 的一个实例让你在缓冲区的任何字节偏移处访问数据,并将该数据解释为几种类例如(Uint8、Float64等)。

这是一个类型化数组API的结构图

typed_array.jpeg

在下表中列出 API 支持的类型

Element typeBytesDescriptionC type
Int818-bit signed integersigned char
Uint818-bit unsigned integerunsigned char
Uint8C18-bit unsigned integer (clamped conversion)unsigned char
Int16216-bit signed integershort
Uint16216-bit unsigned integerunsigned short
Int32432-bit signed integerint
Uint32432-bit unsigned integerunsigned int
Float32432-bit floating pointfloat
Float64864-bit floating pointdouble

这里要特别说一说 Uint8C 元素类型,这个类型并不被 DataView 所支持支持,只为启用Uint8ClampedArray 而存在。这个类型的数组是为 canvas 专用(目的是取代CanvasPixelArray)。Uint8C 和 Uint8的唯一区别是如何处理overflow 和 underflow,这个会在随后给出解释。建议避免使用前者。

因为 PC 对数字表示具有极限能力,由overflow & underflow现象产生的错误叫做Rounding Error。Rounding Error有时会导致系统奔溃,所以我们必须要采用一些方式来避免这种问题。解决问题的思路就是要通过变形,将极大数极小数变形为普通数。

我想说的是,Uint8ClampedArray 完全是因 HTML5 canvas,而遗留的历史问题。除非必须要处理关于 canvas-y,否则要避免。

20.2.2 Handling overflow and underflow Normally, when a value is out of the range of the element type, modulo arithmetic is used to convert it to a value within range. For signed and unsigned integers that means that:

The highest value plus one is converted to the lowest value (0 for unsigned integers). The lowest value minus one is converted to the highest value. Modulo conversion for unsigned 8-bit integers:

处理 overflow 和 underflow

通常情况下,当一个值超出元素类型的范围时,会使用模数运算将其转换为范围内的值。对于有符号和无符号的整数,这意味着:当最高值加 1 被转换为最低值(无符号整数为0)最低值减 1 被转换为最高值。无符号 8 位整数的模数转换。

无符号 8 位整数的模数转换
const uint8 = new Uint8Array(1);
uint8[0] = 255; uint8[0] // 最大值在范围内
255
uint8[0] = 256; uint8[0] // 向上溢出
0
uint8[0] = 0; uint8[0] // 最小值在范围内
0
uint8[0] = -1; uint8[0] // 向下溢出
255
有符号 8 位整数的模数转换
const int8 = new Int8Array(1);
int8[0] = 127; int8[0] // 最大值在范围内
127
int8[0] = 128; int8[0] // 向上溢出
-128
int8[0] = -128; int8[0] // 最小值在范围内
-128
int8[0] = -129; int8[0] // 向下溢出
截断(Clamped)的转换是不同的。
  • 将所有溢出的值转换为最低值
  • 将所有溢出的值转换为最高值
const uint8c = new Uint8ClampedArray(1);
uint8c[0] = 255; uint8c[0] // highest value within range
255
uint8c[0] = 256; uint8c[0] // overflow
255
uint8c[0] = 0; uint8c[0] // lowest value within range
0
uint8c[0] = -1; uint8c[0] // underflow
0