js 字节数组操作,TCP协议组装

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


//Array 与 ArrayBuffer相互转换
ArrayBuffer 转Array
let arrayBuffer = new ArrayBuffer(10);
let array = Array.prototype.slice.call(new Uint8Array(arrayBuffer ));
 //Array转 ArrayBuffer
let array = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
let arrayBuffer = new Uint8Array(array).buffer;


json对象转化为key,value的对象数组

const metaData = {"api-type": "apiparser", "management.port": "8101"}
	let arr= Object.entries(metaData).map(([key, value]) => ({
	key, value
}))

在这里插入图片描述

创建全为0的数组的几种方法

1、for循环

var arr = [];
for(var n=0; n<10; n++){
  arr[n] = 0;    
}
  1. 用ES6中的fill()方法
var arr = new Array(10).fill(0);

3.使用Uint8Array()方法

//生成8位无符号整数值的类型化数组,内容将初始化为0。
var arr = new Uint8Array(10);

扩展操作符三个点(…)

  • 解构赋值
//解构赋值可以从等号右侧的值中提取一个或多个保存到左边的变量中:
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

名称占用字节描述
Int8Array18位二补码有符号整数
Uint8Array18位无符号整数
Uint8ClampedArray18位无符号整型固定数组(数值在0~255之间)
Int16Array216位二补码有符号整数
Uint16Array216位无符号整数
Int32Array432 位二补码有符号整数
Uint32Array432 位无符号整数
Float32Array432 位 IEEE 浮点数
Float64Array864 位 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 属性返回分配字节的长度 8
 
var int8a = new Int8Array(arraybuffer);//类方法ArrayBuffer.isView()判断某对象是否为视图
ArrayBuffer.isView(int8a)  //return true

Array 与 ArrayBuffer相互转换

//ArrayBuffer toArray
let arrayBuffer = new ArrayBuffer(10);

let array = Array.prototype.slice.call(new Uint8Array(arrayBuffer ));
//Array to ArrayBuffer
let array = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
let arrayBuffer = new Uint8Array(array).buffer;

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;
    }

进制转换

字符串转arraybuffer

/**
 * 字符串转arrayBuffrt
 * @param {*} str 需要转换的字符串
 * @returns 返回 arrayBuffer
 */
  strToab (str) {
	var array = new Uint8Array(str.length);
	for(var i = 0; i < str.length; i++) {
		array[i] = str.charCodeAt(i);
	}
	return array.buffer
}

arraybuffer 转字符串

arrayBufferToString(buffer) {
    return String.fromCharCode.apply(null, new Uint8Array(buffer))
}

16进制的字符串转Arraybuffer

 // 16进制字符串转ArrayBuffer
			    hex2ArrayBuffer(hex_str) {
			      // let hex_str = 'AA5504B10000B5'
			      let typedArray = new Uint8Array(hex_str.match(/[\da-f]{2}/gi).map(function (h) {
			        return parseInt(h, 16)
			      }))
			      let buffer = typedArray.buffer
			      return buffer
			    }
 //示例一,将二进制、八进制、十六进制数字解析为十进制数字

parseInt(0101,2);//NaN

parseInt("0101")//101

parseInt("0101",2)//5

parseInt("0101",8)//65

parseInt("0101",10)//101

parseInt("0101",16)//257

//示例二,将十进制数字解析为二进制、八进制、十六进制数字

var x=999;

x.toString(2);//"1111100111"

x.toString(8);//"1747"

x.toString(16);//"3e7"

//示例三,二进制、八进制、十六进制数字相互转换(原理,先转化为十进制)

parseInt('ff',16).toString(2);//十六进制"ff" 转 二进制 "11111111"

parseInt("11111111",2).toString(8);//二进制"11111111" 转 八进制 "377"

16进制的字符串转2进制字符串

// 十六机制字符串"09" 转二级制字符串"00001001 "
var strHex="09";
 var strBin = strHex.toString(2)

数据下发

方案一:
//定义一个字节数组
let  arr= [0x02, 0xB1, 0xC2,  0xD3, 0xE4, 0xF5]	
//字节数组转arraybuffer
let arrayBuffer = new Uint8Array(arr).buffer; 
方案二:
let hex_str = '01A0B1C2D3E4'
 let buffer=this.hex2ArrayBuffer(hex_str)
 

参考连接

链接: https://ext.dcloud.net.cn/plugin?id=12803

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值