创建数组
Array.of()
方法将接收的每个参数作为数组元素创建并返回数组。和 Array 构造器相比,用于函数参数更可靠。
function create(fun, value) {
return fun(value);
}
let items = create(Array.of, value);
Array.of 创建数组使用的是当前 of()
方法中的 this,而不是 Symbol.species 中返回的函数。
Array.from()
方法接收的第一个参数为类数组或可迭代对象时,会返回一个数组,数组中元素的值和顺序由参数中的项(元素)决定。这个方法创建数组时也没有使用 Symbol.species 属性返回的函数。
Array.from()
方法除了接收第一个参数外,第二个参数类型为函数,最终返回的数组元素是由第一个参数提供的元素经过作为第二个参数的函数处理之后得到的。
let arr = Array.from(arrayLike, e => e + 1);
如果 Array.from()
方法的作为第二个参数的函数中使用了某个对象的非方法属性,则需要将对应的对象作为第三个参数。
let obj = {
value : 1,
incre(v) {
return v + this.value;
}
};
// 用到了 obj 的属性 value
let arr = Array.from(arrayLike, obj.incre, obj);
新方法
find()
和 findIndex()
方法的第一个参数为回调函数,第二个参数可选,表示回调函数中的 this 值。回调函数有三个参数,第一个表示值,第二个表示索引,第三个表示数组本身。遍历数组,如果某个元素满足回调函数中的条件时,find()
返回这个元素,findIndex()
返回这个元素的索引。
let arr = [9,8,7,6,3,2,1];
arr.find(e => e < 5); // 3
arr.findIndex(e => e < 5); // 4
fill()
方法使用特定的值填充数组。有三个参数,其中后两个可选。第一个参数表示用于填充数组的值,第二个参数表示填充的起始索引,从该索引开始填充;第三个参数表示填充终止的索引,从该索引开始不再填充。不指定索引时,填充整个数组,即使数组有值,会用第一个参数的值覆盖已存在的值。如果后两个参数的值为负数,则实际索引值为数组长度加上传入的值。
copyWithin()
方法用于选择数组中部分连续的元素替换数组中部分连续的元素。该方法有三个参数,第一个参数表示该索引开始的元素将被替换,第二个参数表示该索引开始的元素将被用于替换其他元素,第三个参数可选,表示用于替换的元素索引到此结束,不包含该索引。如果表示索引的参数为负数,则处理方式与 fill()
一致。
let arr = [1,2,3,4];
arr.copyWithin(2, 0, 1); // [1,2,1,4]
类型化数组
类型化数组是用来存储和处理不同数值类型的元素,为了节省内存。
无论是整数还是浮点数,js 都使用 64 位进行存储,造成了内存的浪费。类型化数组存储和处理的数据类型有 int8/uint8/int16/uint16/int32/uint32/int64/uint64 合计 8 种,每一种占用的内存空间由名称可知。
数组缓冲区(array buffer)类似于 C 语言中 malloc 分配的内存,表示一段连续的内存。创建数组缓冲区时,传入构造器的参数表示分配以字节为单位的内存大小。数组缓冲区一旦创建完成,则不能更改大小。byteLength 属性存储了分配的内存字节数。可以在一个已创建的数组缓冲区上使用 slice()
方法创建新的和已有数组缓冲区共享内存的数组缓冲区。
let ab = new ArrayBuffer(6);
ab.byteLength; // 6
let another = ab.slice(2, 5); // 将 ab 的第 2 到 4 个字节作为新的数组缓冲区
视图提供了处理数组缓冲区的接口。DataView 类型是所有数组缓冲区通用的视图。创建 DataView 时需要向构造器传入一个数组缓冲区表示与该数组缓冲区关联。构造器有三个参数,后两个可选。第一个参数为与视图关联的数组缓冲区,第二个参数为视图允许在数组缓冲区上处理的起始位置,以字节为单位距离数组缓冲区起始地址的偏移量;第三个参数为视图允许在数组缓冲区上处理的范围,以字节为单位。
let ab = new ArrayBuffer(8);
let dv = new DataView(ab);
new DataView(ab, 2, 5); // 允许处理的范围为从第 2 个字节开始连续的 5 个字节
视图有 3 个只读属性:buffer 存储和该视图绑定的数组缓冲区。byteOffset 存储创建视图时传入的第二个参数,也就是距离数组缓冲区首地址的偏移量,创建时没有传参则默认为 0。byteLength 存储创建视图时传入的第三个参数,即视图可处理的范围大小,创建时没有传参则默认为数组缓冲区的 byteLength 属性。
视图提供了 getIntX()
、getUnitX()
、setIntX()
、setUnitX()
、getFloatY()
、setFloatY()
方法读写数据。其中 X 可替换成 8/16/32/64,Y 可替换成 32/64,对应不同的位数。get 有两个参数,第一个参数为从距离视图可处理范围的起始位置的偏移量,从该处读取数据,读取的位数由方法名中的数字决定;第二个参数可选,默认为 false,表示数据是否以低字节优先的方式存储。set 有三个参数,第一个参数和 get 方法一致,表示偏移量,第二个参数表示要写入到该偏移量位置的值,第三个参数可选,与 get 的第二个参数含义一致。低字节优先表示存储一个数时,先将该数的二进制表示的高位存储到低字节位置,然后次高位存储到次低字节位置,按这种方式存储。这些方法读写数据时,根据方法名中的位数读写,这些位存储的数据不影响方法的使用。
let ab = ArrayBuffer(8);
let dv = DataView(ab);
dv.setInt8(0, 100);
dv.getInt8(0); // 100
类型化数组实际上是特定类型视图对数组缓冲区的绑定。类型有 IntXArray、UintXArray、FloatYArray、Uint8ClampedArray。其中 X 可替换成 8/16/32/64,Y 可替换成 32/64,数字表示了该类型可处理的位数。其中 Uint8ClampedArray 和 Unit8Array 的区别为,当数组缓冲区内值溢出时,Uint8ClampedArray 会将其转换成 0(如果值小于 0) 或者 255(如果值大于 255)。
每种类型都有一个 BYTES_PER_ELEMENT 属性表示每种类型可处理的数据所占用的字节数。
创建特定类型视图的第一种方式与创建 DataView 方法一致,同时也具有 DataView 的三个只读属性。
第二种方式是传递单个参数给类型化数组构造器,表示创建的数组允许存储的元素个数。length 属性保存了这个数。如果传递的参数为 0,表示类型化数组没有分配空间,不能存储数据。
let i = new Int8Array(10);
i.length; // 10
i.byteLength; // 10
第三种方式是传递单个对象给类型化数组构造器。允许传递的对象有类型化数组、可迭代对象、数组、类对象数组。传递这些对象时,分别:使用类型化数组的元素初始化新类型化数组、使用可迭代对象元素初始化新类型化数组,如果元素不匹配,抛出错误、使用数组元素初始化新类型化数组,元素不匹配则抛出错误、与传入对象为数组时初始化过程一致。
类型化与常规数组相似点
类型化数组的 length 属性与常规数组一样,表示元素个数,只不过是只读的,不能修改该属性值。类型化数组也是通过数值索引访问元素。
类型化数组有 copyWithin()
、entries()
、fill()
、filter()
、find()
、findIndex()
、forEach()
、indexOf()
、join()
、keys()
、lastIndexOf()
、map()
、reduce()
、reduceRight()
、reverse()
、slice()
、some()
、sort()
、values()
方法,其中有返回值的方法,返回值的类型是类型化数组。
类型化数组也有三个迭代器 entries()
、keys()
、values()
,使用扩展运算符可以将其转换成常规数组。
let int8s = new Int8Array([1,2]);
let ints = [...int8s];
ints instanceof Array; // true
类型化数组的 of()
和 from()
方法与常规数组的一样,除了返回类型是类型化数组。
类型化与常规数组区别
类型化数组创建之后长度保持不变,如果使用不在有效索引范围内的索引时,会忽略该操作。如果向类型化数组中添加无效值或者修改某元素为无效值时,会将无效值转换成 0 再进行处理。
类型化数组没有的方法:concat()
、pop()
、push()
、shift()
、splice()
、unshift()
。
类型化数组特有的两个方法:set()
和 subarray()
。set()
方法有两个参数,第一个参数接收任意类型的数组(无论是常规还是类型化),第二个参数为偏移量,表示从该索引开始将第一个参数的所有元素复制到数组中。subarray()
方法的两个参数都是可选的,第一个参数表示起始索引,第二个参数表示终止索引,将起始索引到终止索引前的一个索引范围内的元素作为一个新的类型化数组的元素,然后创建并返回这个新的类型化数组。
参考
[1] Zakas, Understanding ECMAScript 6, 2017.