Array 的新方法
Array.of
在 JavaScript 中,有两种方法创建一个数组,一个是通过构造函数 Array,另一个是通过字面量 [] 的方式。通过 Array 创建一个数组时,如果传入了一个数字 $n$,表示的是创建一个容量为 $n$ 的数组;如果传入了一个参数,但是不是一个数字,那么会创建一个包含该参数的数组;如果传入多个参数,那么创建一个包含这些参数的数组
let arr = new Array(2); // 创建长度为 2 的数组 |
根据参数个数以及类型的不同,创建出的数组也不同,这种行为可能会为开发者带来记忆上的负担,所以在 ES6 中提供了一个 Array.of 方法,它可以接收多个参数,返回一个数组,数组中的元素就是传入的参数,与参数的个数以及类型无关
let arr = Array.of(2); |
Array.from
Array.from 方法的作用是将一个类数组转化为真正的数组,例如将 arguments 转化为真正的数组
function translateArray() { |
也可以将一个可迭代的对象转化为真正的数组
let obj = { |
Array.from 的第二个参数还可以接收一个回调函数,类似于 map 函数
function translateArray() { |
如果在回调函数中需要用到 this 的话,也可以通过第三个参数传入 this。
find 和 findIndex
find 和 findIndex 都是用来搜索的方法,它们都接收一个回调函数作为条件来进行搜索
let arr = [1, 2, 3, 4, 5]; |
可以通过第二个参数传入回调函数中用到的 this。
fill
fill 方法的作用是将数组中的所有元素填充为指定值
let arr = new Array(5); |
fill 方法还可以接收起始位置和终止位置,表示将数组某个部分填充为指定值
arr.fill(5, 0, 3); // 将 [0, 3) 填充为 5 |
copyWithin
let arr = [1, 2, 3, 4, 5]; |
定型数组
在 JavaScript 中数字都是使用浮点数存储的,即使用 64 位来存储数字,但是在一些特殊的场合,例如对于图像,对于每一个像素只需要 8 位来存储即可,如果使用 64 位存储数据,必然会造成内存上的浪费,并且是 8 倍的浪费,所以就 ES6 就提出了定型数组来针对这些特殊的场景。
ArrayBuffer
所有定型数组的基础都是 ArrayBuffer,它表示占据一定字节的内存区域,通过调用 ArrayBuffer 构造函数,可以分配指定数目字节的内存
let buffer = new ArrayBuffer(10); // 分配 10 个字节的内存 |
输出为
ArrayBuffer { |
DataView
我们可以通过 DataView 来查看和操作 ArrayBuffer
const buffer = new ArrayBuffer(10); |
DataView 构造函数接收一个 ArrayBuffer 对象,除此之外还可以接收两个可选参数
- byteOffset:偏移量,默认是 0
- byteLength:字节长度,默认是 buffer 的长度
// 获得偏移量为 0,长度为 2 字节的 view |
DataView 对象包含如下属性
- buffer:传入构造函数的 ArrayBuffer 对象
- byteOffset:传入构造函数的 byteOffset
- byteLength:传入构造函数的 byteLength
const buffer = new ArrayBuffer(10); |
通过下面的方法可以读取和设置 buffer 中的值
- getInt8(offset, littleEndian)
- setInt8(offset, value, littleEndian)
- getUInt8(offset, littleEndian)
- setUInt8(offset, value, littleEndian)
以上暂且忽略参数 littleEndian
let buffer = new ArrayBuffer(10); |
此外还可以通过下面的方法设置浮点数的值
- getFloat32
- setFloat32
- getFloat64
- setFloat64
接收的参数同上面一样
// 3F 80 00 00 |
定型数组
一个定型数组其实就是一个指定类型 DataView,具体有如下定型数组
向上图中的构造函数传入一个 buffer 创建定型数组,另外还可以传入 byteOffset 和 byteLength 两个可选参数,这两个可选参数的默认值同 DataView
let buffer = new ArrayBuffer(10); |
byteLength 必须能够整除定型数组表示的元素大小,假如向 Int16Array 传入一个大小为奇数的 byteLength,那么会报错,因为 Int16Array 中每个元素占据两个字节,而奇数不能整除 2,即无法平均分配,所以会报错
let int16 = new Int16Array(buffer, 0, 9); // 9 不能整除 2,会报错 |
除此以外,还可以直接传入一个数字,表示分配多少字节的内存给字节数组,同理需要注意传入的数字要能够整除定型数组中每个元素的大小
let int16 = new Int16Array(8); |
如果没有向构造函数传入任何参数时,默认传入的参数为 0,这时定型数组不能保存数据,因为没有为它分配内存空间。
除此以外,定型数组的构造函数还可以接收如下几种类型的参数
- 一个定型数组:将定型数组中的元素一个个的复制到新的定型数组中,所以两个定型数组的 buffer 是不同的
- 一个可迭代的对象:调用对象的默认迭代器,将得到的元素一个个的添加到定型数组中
- 一个数组
- 一个类数组,如 arguments
let int8 = new Int8Array([25, 50]); // 使用数组作为参数 |
定型数组与一般数组的相似之处
在很多的时候,可以把定型数组当做是一般数组
let int8 = new Int8Array([25, 50]); |
定型数组的长度一旦确定就不能再改变
共同方法
定型数组与普通数组有以下共同方法
let int8 = new Int8Array([25, 50]); |
共同的迭代器
定型数组也有三个迭代器,即 entries、keys 和 values,这意味着你可以使用展开运算符和 for … of 循环
let arr = [...int8]; |
of 与 from 方法
定型数组也有 of 和 from 方法
let int8 = Int8Array.of(3, 56); |
定型数组与一般数组的不同之处
行为不同
一般数组的长度是可变的,但是定型数组的长度不可变
let int8 = new Int8Array([0, 1]); |
定型数组会检查传入的数据是否有效,如果无效传入的值会被替换为 0
let int8 = new Int8Array(["hi"]); // 会被替换为 0 |
对定型数组进行修改也会对值的类型进行检查,如果是无效的类型,则值会被替换为 0
let int8 = new Int8Array([1, 2]); |
缺失的方法
定型数组没有以下方法
因为上面的方法都会改变数组的长度,所以定型数组没有以上方法是很容易理解的。
新增的方法
相比于一般数组,定型数组新增了两个方法
- set:将一个数组中的元素复制到定型数组中
- subarray:从定型数组中抽取一部分到新的定型数组中
set 方法接收一个数组,以及一个可选的参数,数据插入的偏移量,如果省略第二个参数,那么偏移量默认为 0
let int8 = new Int8Array(4); // 数组长度为 4 |
subarray 接收两个可选的参数
- start:起始位置,缺省为 0
- end:终止位置,缺省为数组的长度
抽取的范围为 [start, end),左闭右开,返回一个新的定型数组
let int8 = new Int8Array([1, 2, 3, 4]); |