Js定型数组
定型数组
1.ArrayBuffer
ArrayBuffer是所有定型数组及视图引用的基本单位,用于分配空间。
注:ShareArrayBuffer是ArrayBuffer的一个变体,在上下文间自动共享
const buf = new ArrayBuffer(16); // 在内存中分配16字节
console.log(buf.byteLength); // 16
空间中的二进制位都初始化为0
创建后无法改变大小,但是支持slice()方法复制全部或部分
const buf1 = new ArrayBuffer(16);
const buf2 = buf1.slice(4, 12);
console.log(buf2.byteLength); // 8
注:不能直接通过ArrayBuffer实例来读取和写入其内容。
2.DataView
DataView是一种视图,对内容没有预设,不可迭代。
const buf = new ArrayBuffer(16);
// DataView默认使用整个ArrayBuffer
const fullDataView = new DataView(buf);
// 使用部分缓冲
const firstHalfDataView = new DataView(buf, 0, 8);
// 使用剩余缓冲
const secondHalfDataView = new DataView(buf, 8);
console.log(fullDataView.byteOffset); // 0 起始偏移索引
console.log(fullDataView.byteLength); // 16
console.log(fullDataView.buffer === buf); // true
2.1 ElementType
在读写DataView对象时需要指定一种类型,共有8种。
Int8、Uint8、Int16、Uint16、Int32、Uint32、Float32、Float64
每种类型都有 get 和 set 方法 ,接收byteOffset(字节偏移量)和 值
// 在内存中分配两个字节并声明一个DataView
const buf = new ArrayBuffer(2);
const view = new DataView(buf);
console.log(view.getInt8(0)); // 0
view.setUint8(0, 255);
view.setUint8(1, 0xFF);
console.log(view.getInt16(0)); // -1
2.2 字节序
- 大端字节序:最高有效位保存在第一个字节,而最低有效位保存在最后一个字节。(默认)
- 小端字节序:与大端字节序相反
set 和 get 都可以接收额外参数 true 即可启用小端字节序。
view.setUint8(0, 0x80); // 设置最左边的位等于1
view.setUint8(1, 0x01); // 设置最右边的位等于1
// 1000 0000 0000 0001
// 0x8001 = 2^15 + 2^0 = 32768 + 1 = 32769
console.log(view.getUint16(0)); // 32769
// 按小端字节序读取Uint16
// 0x01是高字节,0x80是低字节
// 0x0180 = 2^8 + 2^7 = 256 + 128 = 384
console.log(view.getUint16(0, true)); // 384
// 按小端字节序写入Uint16
view.setUint16(0, 0x0002, true);
// 0x0 0x2 0x0 0x0
// 0000 0010 0000 0000
console.log(view.getUint8(0)); // 2
console.log(view.getUint8(1)); // 0
注:set 和 get 时如果超过缓冲区会抛出RangeError
3.定型数组
相对于DataView它只特定于一种ElementType
3.1 创建
// 1.通过已有缓冲创建
const buf = new ArrayBuffer(12);
const ints = new Int32Array(buf);
// 2.使用自有缓冲创建
const ints2 = new Int32Array(6);
console.log(ints2.length); // 6
// buffer属性为缓冲
console.log(ints2.buffer.byteLength); // 24 = 4*6
// 3.使用可迭代结构填充
const ints3 = new Int32Array([2, 4, 6, 8]);
console.log(ints3[2]); // 6
// 4.基于任意类型定型数组
const ints4 = new Int16Array(ints3);
// 这个新类型数组会分配自己的缓冲
// 对应索引的每个值会相应地转换为新格式
alert(ints4.length); // 4
alert(ints4.buffer.byteLength); // 8 = 2*4
alert(ints4[2]); // 6
// 5.<ElementType>.from()
const ints5 = Int16Array.from([3, 5, 7, 9]);
// 6.<ElementType>.of()
const floats = Float32Array.of(3.14, 2.718, 1.618);
3.2 合并、复制和修改定型数组
-
set():从提供的数组或定型数组中把值复制到当前定型数组中指定的索引位置
// 创建长度为8的int16数组 const container = new Int16Array(8); // 把定型数组复制为前4个值 // 偏移量默认为索引0 container.set(Int8Array.of(1, 2, 3, 4)); console.log(container); // [1,2,3,4,0,0,0,0] // 把普通数组复制为后4个值 // 偏移量4表示从索引4开始插入 container.set([5,6,7,8], 4); console.log(container); // [1,2,3,4,5,6,7,8]
-
subarray():截取原始数组,返回新数组。
const source = Int16Array.of(2, 4, 6, 8); // 把整个数组复制为一个同类型的新数组 const fullCopy = source.subarray(); console.log(fullCopy); // [2, 4, 6, 8] // 从索引1开始复制到索引3 const partialCopy = source.subarray(1, 3); console.log(partialCopy); // [4, 6]
-
自己实现拼接函数
function typedArrayConcat(typedArrayConstructor, ...typedArrays){ const numElements = typedArrays.reduce((pre, cur) => (pre.length||pre) + cur.length); const resultArray = new typedArrayConstructor(numElements); let currentOffset = 0; typedArrays.map((e) => {resultArray.set(e,currentOffset);currentOffset+=e.length}); return resultArray; } const concatArray = typedArrayConcat(Int32Array, Int8Array.of(1,2,3), Int8Array.of(4,5,6), Int8Array.of(7,8,9)); console.log(concatArray);
3.3 下溢和上溢
下溢和上溢不会影响到其他索引,值由实际编码决定
const unsignedInts = new Uint8Array(2);
unsignedInts[1] = 256; // 0x100
console.log(unsignedInts); // [0, 0]
unsignedInts[1] = 511; // 0x1FF
console.log(unsignedInts); // [0, 255]
注:除了8种元素类型,还有一种“夹板”数组类型: Uint8ClampedArray,不允许任何方向溢出。超出最大值255的值会被向下舍入为255,而小于最小值0的值会被向上舍入为0。