摘要:在内部设计时分成了两部分和。层表示内存中的数据块,负责提供操作数据块的接口。也就是说通过创建内存块,通过实现对内存块的读写操作。很显然中的结果是。有同学可能对输出的顺序不理解,觉得为什么不是呢。上例在小端模式下的存储形式,每个框框表示位。
我们知道在C语言中,可以使用malloc和free方法来分配和释放内存。随着web的发展中,js在ES6中新增了内存操作的支持。其实现方式就是---typed array。
typed array是个集体的概念。int8Array,Uint8Array,int16Array,Uint16Array等统统等称为typed array。通过这些类,开发者可以方便地读写内存中的二进制数据。
typed array在内部设计时分成了两部分:buffer和view。buffer层表示内存中的数据块,view负责提供操作数据块的接口。
ArrayBufferbuffer层的底层实现就是基于ArrayBuffer类。ArrayBuffer的功能与malloc类似,为用户分配一块内存。
创建一个ArrayBuffer实例很简单,它接收一个参数,参数表示要分配多大的一块内存区域,字节为单位。下面的代码片段,分配了一块8字节的内存区:
var buffer = new ArrayBuffer(8);
我们还可以通过byteLength访问该实例的内存大小:
console.log(buffer.byteLength) // 8
使用slice方法创建一个新的实例,其内容复制原ArrayBuffer实例中的部分内容。
var buf2 = buffer.slice(0,2);
创建一个新的实例,分配2字节大小的内存,其内容复制buffer中索引为0和1的内存中的数据。
但是ArrayBuffer并不提供对内存读写的方法。如果要对该内存块进行操作,需要用到另一个类DataView。
DataViewDataView类提供了访问ArrayBuffer的接口。其语法如下:
new DataView(buffer [, byteOffset [, byteLength]])
首先接收一个必传的buffer对象,该对象就是DataView实例接下来将要操作的内存块。其次是一个可选的byteOffset,该参数表示DataView实例要操作的buffer对象的开始位置。最后的参数指定要操作的buffer对象中元素的个数。
下面的代码片段演示了DataView如何操作ArrayBuffer:
var buffer = new ArrayBuffer(16); var dv = new DataView(buffer, 0); dv.setInt16(1, 42); dv.getInt16(1); //42
示例中创建了一个DataView实例,该实例将buffer作为被操作的内存块,并且指定该内存块的16个字节都位于可操作区。
接着调用setInt16方法向从buffer的第2个字节开始存储带符号的16位整数。调用getInt16方法读出位于第2个字节处的带符号的16位整数。
如上所述,typed array的实现是组合了ArrayBuffer和DataView。也就是说typed array 通过ArrayBuffer创建内存块,通过DataView实现对内存块的读写操作。
typed array提供了多个类实现对同一块内存中的二进制数据按照不同的位数格式进行读写。如使用int8Array从内存中以带符号的8位整数的形式读写数据。
下面看一个例子来加深对typed array的理解
var buffer = new ArrayBuffer(16) //创建16b的内存区 var int32View = new Int32Array(buffer); var int16View = new Int16Array(buffer); for (var i = 0; i < int32View.length; i++) { int32View[i] = i * 2; console.log(int32View[i]); // 0, 2, 4, 6 } for (var i = 0; i < int16View.length; i++) { console.log(int16View[i]); // 0, 0, 2, 0, 4, 0, 6, 0 }
buffer是一个ArrayBuffer实例,表示一块16b的内存区。同时创建了两个typed array,分别是32位和16位的。区别在于使用32位的访问buffer时,会把buffer(16b)以32位为单位划分为4个元素,读写都是以32位为单位进行的。16位的进行访问时,会把buffer(16b)以16位为单位划分为8个元素,每次读写都是16位。
第一个循环中,我们使用int32View向buffer中的4个元素中分别写入了0,2,4,6 4个整数。
很显然console中的结果是0,2,4,6。
第二个循环中,我们使用int16View以16位的格式读取同一块内存,可以想象原来的4个元素变成了8个元素,因此读出的时候也会将原来的32位元素拆分为2个16位元素。因此console中的结果是0,0,2,0,4,0,6,0。
有同学可能对输出的顺序不理解,觉得为什么不是0,0,0,2,0,4,0,6呢。这里稍微解释一下。
原因是默认情况下typed array 读取数据的时候都是以小端模式来返回的。
所谓的小端模式(Little-endian),是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
上例在小端模式下的存储形式,每个框框表示16位。小端模式下数据的位权和地址的顺序是一致的,从小到大排列。
总结typed array提供了一组读取不同字长的类数组对象如,int8Array,int16Array,int64Array来实现对内存的操作。typed array的底层实现是基于ArrayBuffer和DataView实现的,对内存的分配和内存的读取做了很好的分层设计。使用typed array使js向C语言等具备了操作二进制数据的能力。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/90116.html
摘要:类型化数组也是中新引入的。用一句话解释类型化数组就是它是操作二进制数据的接口。类型化数组类型化数组的应用二进制数据的接口主要应用于文件,在中涉及文件处理的几乎都可以应用,主要是,,。 类型化数组(Typed Array)也是HTML5中新引入的API。用一句话解释类型化数组就是:它是JS操作二进制数据的接口。 众所周知,直接操作二进制数据可以使程序更为高效, 尽管JS对常规数组做了很多...
摘要:闭包的形成与变量的作用域以及变量的生存周期密切相关。现在我们把变量用闭包封闭起来,便能解决请求丢失的问题二高阶函数高阶函数是指至少满足下列条件之一的函数。回调函数在异步请求的应用中,回调函数的使用非常频繁。 一、闭包 对于 JavaScript 程序员来说,闭包(closure)是一个难懂又必须征服的概念。闭包的形成与变量的作用域以及变量的生存周期密切相关。下面我们先简单了解这两个知识...
摘要:调用函数,判断返回的类型字符串,就知道是什么数据类型了判断是否为浏览器的对象要为对象首先要满足的条件是不能为或者,并且为自身的引用。必须存在中必须存在属性返回的值调用函数,返回的数据类型。 数组方法 定义 var emptyArray = [] concat = emptyArray.concat filter = emptyArray.filter slice...
摘要:只要输入的值不变,每次输出都是一样的值。指定位置元素运算操作如可用以下方式代替主要是生成中最核心的对象。描述发生了什么,是响应并对进行更新。生成的对象包含个方法,分别为,和。按照约定,具有字段来表示它的类型。 前言: 一开始接触redux的时候最令我记住的一句话是:You Might Not Need Redux(那我还写这篇文章干嘛?手动滑稽) 回归正题,本文主要是围绕redux...
阅读 854·2023-04-26 03:03
阅读 2161·2021-10-12 10:12
阅读 1145·2021-09-24 09:48
阅读 1599·2021-09-22 15:25
阅读 3250·2021-09-22 15:15
阅读 883·2019-08-29 16:21
阅读 1009·2019-08-28 18:00
阅读 3392·2019-08-26 13:44