JS 的二进制家族一

历史上 JavaScript 是没有读写二进制数据能力的,但随着 es5 中 Blob 对象的引入以及 es6 中 ArrayBuffer 对象、TypedArray 和 DataView 对象的规范化, JS 处理二进制数据的能力大幅度增强,也能直接处理文件流,网络流等二进制 Buffer 数据了。
在这里插入图片描述

  1. Buffer:Buffer 是 Node.js 中的一个内置模块,用于处理二进制数据。
    主要用于在服务器端处理数据。
  2. ArrayBuffer:是 JavaScript 中的内置对象,用于表示通用的、固定长度的原始二进制数据缓冲区,不能直接读写,但可以使用 TypedArray 对象或 DataView 对象进行操作。通常用于在浏览器中进行底层的二进制数据处理。
  3. Blob:是 JavaScript 中的内置对象,用于表示二进制大对象的接口,可以包含各种类型的数据,包括文本和二进制数据。通常用于处理文件数据、通过 Fetch API 发送二进制数据等。
  4. Flie:是 JavaScript 中的内置对象,继承自 Blob,是 Blob 的子类,添加了一些额外的文件相关属性。通常用于处理文件数据。

ArrayBuffer:

ArrayBuffer 代表存储二进制数据的一段内存,它不能直接读写,只能通过 TypedArray 视图和 DataView 视图来读写。

视图的作用是以指定格式解读二进制数据。

创建 ArrayBuffer:

通过 ArrayBuffer 构造函数可以创建一段存放二进制数据的连续内存区域。

let buf = new ArrayBuffer(32) // 创建了一个长度为 32 个字节的连续内存区域。由于没有赋初始值,每一个字节单元的值都默认是 0。

实例属性:

  1. ArrayBuffer.prototype.byteLength:只读属性,返回所分配的内存区域的字节长度。

实例方法:

  1. ArrayBuffer.prototype.slice(start, len):用来拷贝自身的一部分生成一个新的 ArrayBuffer 对象并返回。参数 start 为开始的位置;len 为拷贝的长度。

静态方法:

  1. ArrayBuffer.isView():返回一个布尔值,表示参数是否为 ArrayBuffer 的视图实例。

    也就是,是否为 TypedArray 实例或 DataView 实例。

视图:

ArrayBuffer 在内存中存储的是一段未加工的二进制数据,这一段二进制数据本身只是内存中存储的0、1数据,通过不同的格式来解读就会赋予它不同的意义,这就是视图。

ArrayBuffer 有两种视图,一种是 TypedArray 视图,另一种是 DataView 视图,两者的区别主要是字节序,前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型。

TypedArray:

TypedArray 对象一共提供 9 种类型的视图,每一种视图都是一种构造函数:

  1. Int8Array:8位有符号整数,长度1个字节。
  2. Uint8Array:8位无符号整数,长度1个字节。
  3. Uint8ClampedArray:8位无符号整数,长度1个字节,溢出处理不同。
  4. Int16Array:16位有符号整数,长度2个字。
  5. Uint16Array:16位无符号整数,长度2个字节。
  6. Int32Array:32位有符号整数,长度4个字节。
  7. Uint32Array:32位无符号整数,长度4个字节。
  8. Float32Array:32位浮点数,长度4个字节。
  9. Float64Array:64位浮点数,长度8个字节。
let buf = new ArrayBuffer(32)
let int32 = new Int32Array(buf)
let uint8 = new Uint8Array(buf)
console.log(int32[0]) // 0
console.log(uint8[0]) // 0
	
// 还可以直接修改
int32[0] = 1
console.log(int32[0]) // 1
console.log(uint8[0]) // 1。由于两个视图对应的是同一段内存,一个视图修改底层内存,会影响到另一个视图。
TypedArray 提供的 9 中构造函数的用法:

TypedArray(buffer, byteOffset=0, length):第一个参数 buffer 为可以底层 ArrayBuffer、数组或类数组、数字、ArrayBuffer 视图;第二个参数 byteOffset 为开始字节序号,默认为 0,第三个参数 length 为长度,默认直到本段内存区域结束。返回生成的对象,统称为 TypedArray 对象。

// 创建一个 8 字节的 ArrayBuffer
let buf = new ArrayBuffer(8)

// 创建一个指向 buf 的 Int32 视图,开始于字节 0,直到缓冲区的末尾
let typedAry = new Int32Array(buf)
属性:
  1. TypedArray.prototype.buffer:返回整段内存区域对应的 ArrayBuffer 对象。
  2. TypedArray.prototype.byteLength:返回 TypedArray 数组占据的内存长度,单位为字节。
  3. TypedArray.prototype.byteOffset:返回 TypedArray 数组从底层 ArrayBuffer 对象的哪个字节开始。
  4. TypedArray.prototype.length:表示TypedArray 数组含有多少个成员。

    byteLength 是字节长度,length 是成员长度。

实例方法:
  1. TypedArray.prototype.set():用于复制 TypedArray 数组,也就是将一段内容完全复制到另一段内存。
  2. TypedArray.prototype.subarray(start, end):对于 TypedArray 数组的一部分,再建立一个新的视图。
  3. TypedArray.prototype.slice():返回一个指定位置的新的 TypedArray 实例。
静态方法:
  1. TypedArray.of():TypedArray 数组的所有构造函数,都有一个静态方法 of(),用于将参数转为一个 TypedArray 实例。
  2. TypedArray.from():接受一个可遍历的数据结构(比如数组)作为参数,返回一个基于这个结构的 TypedArray 实例。
TypedArray 类型化数组和正常数组的异同点:

这 9 个构造函数生成的对象,统称为 TypedArray 对象。它们很像正常数组,都有 length 属性,都能用方括号运算符 [] 获取单个元素,所有数组的方法,在这些类型化数组上面都能使用。两者的差异主要在以下方面:

TypedArray 数组也可以转换回普通数组:var normalArray = Array.prototype.slice.call(typedArray)

  1. TypedArray 数组的所有成员,都是同一种类型和格式。
  2. TypedArray 数组的成员是连续的,不会有空位。
  3. TypedArray 类型化数组成员的默认值为0(比如:new Array(10) 返回一个正常数组,里面没有任何成员,只是10个空位;new Uint8Array(10) 返回一个类型化数组,里面 10 个成员都是0)。
  4. TypedArray 数组只是一层视图,本身不储存数据,它的数据都储存在底层的 ArrayBuffer 对象之中,要获取底层对象必须使用 buffer 属性。
DataView 对象:

不同于类型化数组,一个数组只能存放同一类型的数据,DataView 可以在内存中存放不同类型的数据。

let buf = new ArrayBuffer(32)
let dataView = new DataView(buf)
dataView.getUnt8(0) // 建立 DataView 视图,然后以不带符号的 8 位整数格式,读取第一个元素
DataView() 构造函数:

DataView 视图本身也是构造函数,接受一个 ArrayBuffer 对象作为参数,生成视图。

let buffer = new ArrayBuffer(32)
let dv = new  DataView(buffer)
方法:
读取内存的方法:

都接受两个参数:第一个参数都是一个字节序号(不能是负数,否则会报错),表示从哪个字节开始读取;如果一次读取两个或两个以上字节,就必须明确数据的存储方式,到底是小端字节序还是大端字节序,默认情况下,DataView 的 get 方法使用大端字节序解读数据,如果需要使用小端字节序解读,必须在 get 方法的第二个参数指定 true。

  1. getInt8:读取 1 个字节,返回一个 8 位整数。
  2. getUint8:读取 1 个字节,返回一个无符号的 8 位整数。
  3. getInt16:读取 2 个字节,返回一个 16 位整数。
  4. getUint16:读取 2 个字节,返回一个无符号的 16 位整数。
  5. getInt32:读取 4 个字节,返回一个 32 位整数。
  6. getUint32:读取 4 个字节,返回一个无符号的 32 位整数。
  7. getFloat32:读取 4 个字节,返回一个 32 位浮点数。
  8. getFloat64:读取 8 个字节,返回一个 64 位浮点数。
let buffer = new ArrayBuffer(32)
let dv = new  DataView(buffer)

// 从第1个字节读取一个8位无符号整数
var v1 = dv.getUint8(0);

// 小端字节序
var v1 = dv.getUint16(1, true)
写入内存的方法:

都接受三个参数:第一个参数是字节序号,表示从哪个字节开始写入;第二个参数为写入的数据;对于那些写入两个或两个以上字节的方法,需要指定第三个参数,false 表示使用大端字节序写入,true 表示使用小端字节序写入,默认是大端字节写入。

  1. setInt8:写入 1 个字节的 8 位整数。
  2. setUint8:写入 1 个字节的 8 位无符号整数。
  3. setInt16:写入 2 个字节的 16 位整数。
  4. setUint16:写入 2 个字节的 16 位无符号整数。
  5. setInt32:写入 4 个字节的 32 位整数。
  6. setUint32:写入 4 个字节的 32 位无符号整数。
  7. setFloat32:写入 4 个字节的 32 位浮点数。
  8. setFloat64:写入 8 个字节的 64 位浮点数。
// 在第1个字节,以大端字节序写入值为25的32位整数
dv.setInt32(0, 25, false)

ArrayBuffer 和 Blob 的区别:

  1. ArrayBuffer 更底层,就是一段纯粹的内存上的二进制数据,可以对其任何一个字节进行单独的修改,也可以根据需要以指定的形式读取指定范围的数据。
  2. Blob 就是将一段二进制数据进行了一个封装,得到的就是一个整体,可以看到它整体属性大小、类型,可以对其进行分割,但不能了解它的细节。
  3. Blob 可以接收一个 ArrayBuffer 作为参数生成一个 Blob 对象,此行为就相当于对 ArrayBuffer 数据做一个封装,之后就是以整体的形式展现了。
  4. 由于 ArrayBuffer 和 Blob 的特性,Blob 作为一个整体文件,适合用于传输;而只有需要关注细节的时候(比如要修改一段数据),才需要用到 ArrayBuffer。

ArrayBuffer 和 JS 原生数组的区别:

  1. ArrayBuffer 初始化后固定大小,而 JS 数组可以自由增减。
  2. 数组放在堆中,ArrayBuffer 把数据放在栈中。
  3. ArrayBuffer 没有 push/pop 等数组的方法。
  4. ArrayBuffer 读写要借助 TypeArray/DataView。

Blob:

一个 Blob 对象就是一个包含只读原始数据的类文件对象。

创建 Blob:

通过 new Blob(dataArray, option) 创建 Blob 对象。

  1. dataArray:是一个数组,包含了要添加到 Blob 对象中的数据,可以是任意多个 ArrayBuffer、ArrayBufferView、 Blob 或者 DOMString对象。
  2. option:是一个对象,用于设置 Blob 对象的一些属性。
let div = "<div>我是div</div>"
let blob = new Blob([div], {type:'text/html'}) // Blob(13) {size: 13, type: "text/html"}

属性:

  1. size:只读,Blob 对象包含的数据大小(字节)。
  2. type:只读,该 Blob 对象所包含的 MIME 类型。

方法:

  1. slice(start, end):用来对 Blob 进行分割,返回一个新的 Blob 对象,包含了源 Blob 对象中指定范围内的数据。

Blob URL:

Blob URL 是 Blob 协议的 URL,可以通过 URL.createObjectURL(blob) 创建,它的格式如下:blob:http://XXX

Blob URL 和 DataURL 的区别:

  1. Blob URL的长度一般比较短,但 Data URL 因为直接存储图片 Base64 编码后的数据,往往很长。

    当显式大图片时,使用Blob URL能获取更好的可能性。

  2. Blob URL可以方便的使用 XMLHttpRequest 获取源数据,对于Data URL,并不是所有浏览器都支持通过 XMLHttpRequest 获取源数据的。
  3. Blob URL 只能在当前应用内部使用,把 Blob URL 复制到浏览器的地址栏中,是无法获取数据的。Data URL 相比之下,就有很好的移植性,可以在任意浏览器中使用。

通过操作 Blob 可以实现的功能:

  1. 文件下载:通过 window.URL.createObjectURL() 方法,接收一个Blob(File)对象,将其转化为Blob URL;然后赋给 a.download 属性,以用来实现文件的下载。

    <a id="download">文件下载</a>
    
    let blob = new Blob(['Hello World'])
    let url = window.URL.createObjectURL(blob)
    
    let a = document.getElementById('download')
    a.download = 'hellworld.txt'
    a.href = url
    

    在这里插入图片描述

  2. 图片显示:通过 window.URL.createObjectURL() 方法,接收一个Blob(File)对象,将其转化为Blob URL;然后赋给 img.src 属性,以用来实现图片的本地显示。

    <input type="file"/>
    <img id="img" style="width:200px;height:200px"/>
    
    let input = document.getElementsByTagName('input')[0]
    input.addEventListener('change', ()=>{
    	let url = window.URL.createObjectURL(input.files[0])
    	let img = document.getElementById('img')
        img.src= url
    })
    

    在这里插入图片描述

  3. 文件分片上传:通过 Blob.slice(start, end) 可以分割大 Blob 为多个小 Blob。

    <input type="file"/>
    
    let input = document.getElementsByTagName('input')[0]
    input.addEventListener('change', ()=>{
    	let blob = input.files[0]
        let CHUNK_SIZE = 20
    	let SIZE = blob.size
    	let start = 0
    	let end = CHUNK_SIZE
    	 while( start < SIZE) {
    		  console.log(blob.slice(start, end))
    		  start = end
    		  end = start + CHUNK_SIZE
    	 }	 })
    

在这里插入图片描述

File:

File 对象继承自 Blob 对象,在 Blob 的基础上增加了一些属性。

File.prototype instanceof Blob  // true

最常见的 File 对象来自 <input type='file' /> 选择的 FileList 对象或者是使用拖拽操作搞出的 DataTransfer 对象。

<input type="file"/>

let input = document.getElementsByTagName('input')[0]
input.addEventListener('change', ()=>{
    console.log(input.files)
})

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值