viviier

Javascript的“强类型数组”

Javascript的“强类型数组”

引言

对于Javascript中的数组,大家可能会马上想到:

1
2
3
4
5
let arr = [46,456,465,798];
let arr2 = new Array()
arr2[0] = 46
arr2[1] = 456 ...

很方便的我们就创建了arr,arr2两个数组。在我们的印象中,对Array对象已经跟数组划分为同一个东西了,可其实它是一个从哈希表扩展的结构体,它提供了push`splice等一些操作,而它们的效率是很低的。在Javascript中可以创建真正的数组,那就是强类型数组。

在了解什么是强类型数组之前,我们先来看一道题目:

不使用loop循环,创建一个长度为100的数组,并且每个元素的值等于它的下标。

我们来分析:第一步,创建一个长度为100的数组,第二步,让每个元素的值等于它的下标,不能使用使用循环。写成代码就是:

1
2
3
let arr = new Array(100)
arr.map((item, index) => index)
console.log(arr)

是不是感觉很简单,那么我们马上去控制台看看输出了我们想要结果没有:

图片

结果是空的,只有长度却没有内容,我们再在jsbin的console里面看看输出了什么:

图片2

有一个长度为100的,内容全都是undefined的数组,也就是说map方法并没有帮助我们获取到index。这是因为Javascript数组是稀疏数组,虽然长度是100,单实际上是一个空数组,里面没有真实存在的元素,所以使用map方法,是不会去遍历这个数组100次的,因此需要让这个数组有内容:

1
let arr = new Array(100).join(',').split(',')

我们先用join方法将这100个数组通过”,”逗号合并为一个字符串,然后再以”,”逗号为分割符把字符串分割为数组,就得到了一个长度为100的,“空”数组:

图片3

然后再通过.map方法来改变元素的值:

1
2
3
let arr = new Array(100).join(',').split(',')
let newArr = arr.map((item, index) => index)
console.log(newArr)

就得到了我们想要的结果:

图片4

让我们看一下最终代码做了些什么,先是创建一个数组,然后通过join方法把它转换成字符串,然后再通过split方法把字符串转换成数组,最后再通过map函数改变数组内的值。那么有没有一种创建出来直接就可以进行map方法的数组呢?答案是有的,那就是javascript的强类型数组。

“强类型数组”简介

概述

随着Javascript的发展,Javascript现在可以调用一些系统底层的东西乳WebGL,这些底层的操作需要直接访问内存,而Javascript本身的Array在内存中是分散无法与底层操作对接,因此引入了这些强类型的数组。

强类型数组有三种基本类型:

  1. Int 整数
  2. Uint 无符号整数
  3. Float IEEE754 浮点数

根据这些基本类型可以引申出8中类数组:

  1. Int8Array
  2. Uint8Array
  3. Ini16Array
  4. Uint16Array
  5. Int32Array
  6. Uint32Array
  7. Float32Array
  8. Float64Array

这些类数组的规律性很强,命名都是: 基本类型+位数+Array。我们都知道一个字节是8位的,所以8位的数组中每个元素就占一个字节。同理可知64位的数组每个元素占8个字节。就拿Int8Array来说,它是8位的整数。8位可以表示28=256个数字。而Int是有符号的,所以Int8Array的元素可以表示-128到127的整数。而Uint8Array的元素是无符号的,同理可知它可以表示0-255的整数。由于这些数组是使用线性储存,因此它们是定长的,无法给数组添加元素。超出索引的赋值不会报错,也不会生效。

使用

简单调用

通过new一个(基本类型)+(位数)+Array就可以得到一个我们想要的数组:

1
2
let a = new Uint8Array(5)
console.log(a)

在这里我们得到了长度为5的8位无符号整形的空数组:

图片5

我们还可以通过传递一个array对象来把它转换为强类型数组:

1
2
3
let arr = [1,2,3]
let a = new Uint8Array(arr)
console.log(a)

这样会得到一个跟Array对象相同数据的强类型数组:

图片6

这是最常用的两种创建方式。第一种传入数组大小,创建与传入值相同长度的数组,并且把数组内的元素都初始化为0。第二种传入Array对象进行转换,这样得到的数组每一项的值就是原来Array对象中每一项的值,而遇到无法转换的(如英文字符串等)则被置为0:

1
2
let a = new Uint8Array(['123','xyz',456])
console.log(a) // [123, 0, 200]

这里的’123’会被正常输出,而’xyz’则因为无法转换输出0,而456是因为8位职能表示0-255的整数,因此如果要正常输出,则需将new Uint X Array改为16位或32位。

除了这两种创建方式外,还有一种不常用的方式。ArrayBuffer,传入一块内存指针来创建数组。ArrayBuffer的功能和C语言中的malloc相似,申请一块连续的内存,只不过它不需要手动释放内存。ArrayBuffer的返回值是一个封装成了对象的指针,下面是使用例子:

1
2
3
let buf = new ArrayBuffer(4)
let a = new Uint16Array(buf)
console.log(a)

这里输出的结果是:

图片7

这个测试我就不截图了,a这个数组只有两个元素。因为Uint16Array是16位的,也就是每个元素占两个字节。而之前申请的内存控件是4个字节,因此生成的数组只有两个元素。

实例

说了这么多,相信你也大概了解了Javascript中的“强类型数组”是个什么东西,那么让我们回到开始的那道题,new一个强类型的数组会自动的把数组内的元素都初始化为0,因此我们无需再去使用需要通过join和split填充的Array对象,只需要new一个Uint8Array无符号的整形,然后进行map方法改变数组内的值即可:

1
2
let arr = new Uint8Array(100).map((item, index) => index)
console.log(arr)

这样输出的arr为:

图片8

这样使用Javascript的”强类型数组“也很方便的完成了题目的要求。

结语

这篇文章主要是介绍Javascript中的“强类型数组”的基本概念以及它的一些使用方法,如果想要深入研究,可以去查阅官方文档。

附录

参考文章

渔歌 - 阿里前端笔试总结

次碳酸钴 - JavaScript的“强类型数组”简介

拓展阅读

MDN: JavaScript typed arrays

javascript中的稀疏数组(sparse array)和密集数组

关于题目的另外解法

除了使用join,split以及创建一个“强类型数组”外,这道题目还有另外两种方法可以解决。

  1. 使用间歇性定时器setInterval
1
2
3
4
5
6
7
8
let a = [],
i = 0
let interval = setInterval(function() {
i < 100 ? a.push(i++) : clearInterval(interval)
}, 0)
console.log(a)

通过一个计数器来进行自增push值。

2.使用ES6的Array.from方法

1
2
let a = Array.from(Array(100).keys())
console.log(a)

这段代码还可以简写为:

1
2
let a = [...Array(100).keys()]
console.log(a)

个人更推荐使用ES6的[…Array(100).keys()]这种方法

------本文结束感谢阅读------