js 字节数组操作,TCP协议组装
js字节数组,进制转换
- js基础知识
- 数组 Array
- 扩展操作符三个点(...)
- ArrayBuffer
- slice() 数组复制
- reduce 对数组中的每个元素执行一个提供的函数,将其结果汇总为单个返回值
- splice 数组删除,添加,替换
- js 字节数组转数字以及数字转字节数组
js基础知识
数组 Array
- js数组是js中的一种特殊的(内置)对象,索引更像是属性名,只是刚好是整数。
- 在js中,数组是无类型限制的(即数组的元素可以是任意类型,包括自定义对象)。
- js数组是基于零且使用32位数值索引的(从最小0到最大2^32-2)
- js数组是动态的
- js数组可以是稀疏的(即元素不一定有连续的索引,中间可能有缝隙) 对于稀疏数组,length是大于所有元素的最高索引。
- 数组从Array.prototype继承属性,这个原型定义了很多数组操作方法。(并且很多都是泛型的)
var arr1 = new Array(); //创建空数组
var arr2 = new Array(20); //创建一个包含20项的数组
var arr3 = new Array(1,2,3) //包含三个数值的数组
var arr4 = []; //创建一个空数组
var arr5 = [20]; // 创建一个包含1项的数组
var arr6 = [1.1,true,"a",]; // 创建一个包含3个不同类型元素的数组
//如果数组字面量中连续包含多个逗号,且逗号之间没有值,则这个数组为稀疏数组
let count = [1,,3]; //索引0和2有元素,索引1没有元素,但是按索引访问时返回undefined//数组字面量允许末尾出现逗号因此[ , ,]的长度是2不是3
扩展操作符三个点(…)
- 解构赋值
//解构赋值可以从等号右侧的值中提取一个或多个保存到左边的变量中:
let [a, b] = [1, 2] //let a=1, b=2
//通常情况左侧多余的变量会被设置为undefined,右侧多余的变量会被忽略:
let [a, b] = [1] //a==1, y==undefined
[a,b] = [1, 2, 3] //a==1, b==2
- 用于展开数组的元素:
let a = [1, 2, 3]
let b = [0, ...a, 4] //b == [0, 1, 2, 3, 4]
ArrayBuffer
名称 | 占用字节 | 描述 |
---|---|---|
Int8Array | 1 | 8位二补码有符号整数 |
Uint8Array | 1 | 8位无符号整数 |
Uint8ClampedArray | 1 | 8位无符号整型固定数组(数值在0~255之间) |
Int16Array | 2 | 16位二补码有符号整数 |
Uint16Array | 2 | 16位无符号整数 |
Int32Array | 4 | 32 位二补码有符号整数 |
Uint32Array | 4 | 32 位无符号整数 |
Float32Array | 4 | 32 位 IEEE 浮点数 |
Float64Array | 8 | 64 位 IEEE 浮点数 |
Unit8Array 指的是,把 ArrayBuffer 的每个 byte(8-bit) 当作一个单独的无符号整型数字 (0 - 255)
Unit16Array 表示为使用 16 bits (2 bytes) 表示一个无符号整型 (0 ~ 2^16-1) 的数的数组
Int8Array 表示使用 8 bits 表示一个有符号整型 (-128 ~ 127)Float32Array 表示使用 32 bits 表示一个浮点数Unit7ClampedArray 在 0 ~ 255 范围内和 Unit8Array 是一样的,对超出范围的处理有所不同,和图像处理相关(一般像素范围也是 0 ~ 255)
-
每个ArrayBuffer对象表示的只是内存中指定的字节数;
-
但不会指定这些字节用于保存什么类型的数据;
-
通过ArrayBuffer能做的,就是为了将来使用而分配一定数量的字节.
var arraybuffer = new ArrayBuffer(8);//实例化时,仅需传入字节数 生成了字节长度为8的内存区域
ArrayBuffer.length; // 1
arraybuffer.byteLength; // 通过提供的 byteLength 属性返回分配字节的长度 8var int8a = new Int8Array(arraybuffer);//类方法ArrayBuffer.isView()判断某对象是否为视图
ArrayBuffer.isView(int8a) //return true
slice() 数组复制
通过索引位置获取新的数组,该方法不会修改原数组,只是返回一个新的子数组。
用法:arrayObj.slice(start,end)
arrayObj - 原始数组;
start - 必填;设定新数组的起始位置;如果是负数,则表示从数组尾部开始算起(-1
指最后一个元素,-2 指倒数第二个元素,以此类推)。
end - 可选;设定新数组的结束位置;如果不填写该参数,默认到数组结尾;如果是负数,则表示从数组尾部开始算起(-1 指最后一个元素,-2
指倒数第二个元素,以此类推)。
例1:获取仅包含最后一个元素的子数组
var arr=[1,2,3,4,5];
arr.slice(-1);//[5]例2:获取不包含最后一个元素的子数组
var arr=[1,2,3,4,5];
arr.slice(0, -1);//[1,2,3,4]例3:获取包含 从第二个元素开始的所有元素的子数组
var arr=[1,2,3,4,5];
arr.slice(1);//[2,3,4,5]
reduce 对数组中的每个元素执行一个提供的函数,将其结果汇总为单个返回值
reduce方法可做的事情特别多,就是循环遍历能做的,reduce都可以做,比如数组求和、数组求积、数组中元素出现的次数、数组去重等等。
语法
arr.reduce(function(prev,cur,index,arr){
...
}, init);
参数:
prev 必需。累计器累计回调的返回值; 表示上一次调用回调时的返回值,或者初始值 init;
cur 必需。表示当前正在处理的数组元素;
index 可选。表示当前正在处理的数组元素的索引,若提供 init 值,则起始索引为- 0,否则起始索引为1;
arr 可选。表示原数组;
init 可选。表示初始值。
splice 数组删除,添加,替换
array.splice(index,howmany,item1,…,itemX)
参数 | 描述 |
---|---|
index | 必需。规定从何处添加/删除元素。 该参数是开始插入和(或)删除的数组元素的下标,必须是数字。 |
howmany | 可选。规定应该删除多少元素。必须是数字,但可以是 "0"。 如果未规定此参数,则删除从 index 开始到原数组结尾的所有元素。 |
item1, ..., itemX | 可选。要添加到数组的新元素 |
//移除数组的第三个元素,并在数组第三个位置添加新元素:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2,1,"Lemon","Kiwi");
fruits 输出结果:
Banana,Orange,Lemon,Kiwi,Mango//从第三个位置开始删除数组后的两个元素:
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2,2);
fruits 输出结果:
Banana,Orange
js 字节数组转数字以及数字转字节数组
javascript通过ArrayBuffer和DataView实现字节数组和数字之间的相互转换
这里的所有函数用的都是大端字节序(高位在前,低位在后),即数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中
举例:2个字节的无符号整型1的二进制表示
大端模式: 0000 0000 0000 0001
小端模式: 0000 0001 0000 0000
//构建一个视图,把字节数组写到缓存中,索引从0开始,大端字节序function getView(bytes) {var view = new DataView(new ArrayBuffer(bytes.length));for (var i = 0; i < bytes.length; i++) {view.setUint8(i, bytes[i]);}return view;}//将字节数组转成有符号的8位整型,大端字节序function toInt8(bytes) {return getView(bytes).getInt8();}//将字节数组转成无符号的8位整型,大端字节序function toUint8(bytes) {return getView(bytes).getUint8();}//将字节数组转成有符号的16位整型,大端字节序function toInt16(bytes) {return getView(bytes).getInt16();}//将字节数组转成无符号的16位整型,大端字节序function toUint16(bytes) {return getView(bytes).getUint16();}//将字节数组转成有符号的32位整型,大端字节序function toInt32(bytes) {return getView(bytes).getInt32();}//将字节数组转成无符号的32位整型,大端字节序function toUint32(bytes) {return getView(bytes).getUint32();}//将字节数组转成32位浮点型,大端字节序function toFloat32(bytes) {return getView(bytes).getFloat32();}//将字节数组转成64位浮点型,大端字节序function toFloat64(bytes) {return getView(bytes).getFloat64();}//将数值写入到视图中,获得其字节数组,大端字节序function getUint8Array(len, setNum) {var buffer = new ArrayBuffer(len); //指定字节长度setNum(new DataView(buffer)); //根据不同的类型调用不同的函数来写入数值return new Uint8Array(buffer); //创建一个字节数组,从缓存中拿取数据}//得到一个8位有符号整型的字节数组,大端字节序function getInt8Bytes(num) {return getUint8Array(1, function (view) { view.setInt8(0, num); })}//得到一个8位无符号整型的字节数组,大端字节序function getUint8Bytes(num) {return getUint8Array(1, function (view) { view.setUint8(0, num); })}//得到一个16位有符号整型的字节数组,大端字节序function getInt16Bytes(num) {return getUint8Array(2, function (view) { view.setInt16(0, num); })}//得到一个16位无符号整型的字节数组,大端字节序function getUint16Bytes(num) {return getUint8Array(2, function (view) { view.setUint16(0, num); })}//得到一个32位有符号整型的字节数组,大端字节序function getInt32Bytes(num) {return getUint8Array(4, function (view) { view.setInt32(0, num); })}//得到一个32位无符号整型的字节数组,大端字节序function getUint32Bytes(num) {return getUint8Array(4, function (view) { view.setUint32(0, num); })}//得到一个32位浮点型的字节数组,大端字节序function getFloat32Bytes(num) {return getUint8Array(4, function (view) { view.setFloat32(0, num); })}//得到一个64位浮点型的字节数组,大端字节序function getFloat64Bytes(num) {return getUint8Array(8, function (view) { view.setFloat64(0, num); })}下面几个为另一种实现方式的版本,只实现了简单几种,其他的实现起来比较麻烦,所以就中途放弃了function toInt32(bytes) {return ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) | ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);}function toUInt16(bytes) {return ((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF);}function toInt16(bytes) {return bytes[0] >> 7 == 0 ? toUInt16(bytes) : toUInt16(bytes) - 65536;}function getInt32Bytes(num) {return [num >> 24 & 0xFF, num >> 16 & 0xFF, num >> 8 & 0xFF, num & 0xFF];}function getUint16Bytes(num) {return [num >> 8 & 0xFF, num & 0xFF];}function getInt16Bytes(num) {return num >= 0 ? getUint16Bytes(num) : getUint16Bytes(65536 + num);}
``//将数值写入到视图中,获得其字节数组,大端字节序function getUint8Array(len, setNum) {var buffer = new ArrayBuffer(len); //指定字节长度setNum(new DataView(buffer)); //根据不同的类型调用不同的函数来写入数值var uint8Array = new Uint8Array(buffer); //创建一个字节数组,从缓存中拿取数据var arr = new Array(); //将Uint8Array转成Array数组,不考虑性能问题for (var i = 0; i < uint8Array.byteLength; i++) { arr.push(uint8Array[i]);}return arr;}