JavaScript稀疏数组与孔hole示例详解

 更新时间:2022年06月27日 10:01:02   作者:csRyan  
这篇文章主要为大家介绍了JavaScript稀疏数组与孔hole示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

稀疏数组是什么

在绝大多数JavaScript的实现中,数组是稀疏的,我们可以认为js的数组都是稀疏的(虽然ES标准并没有这样规定)。

稀疏数组与密集数组最大的不同,就是稀疏数组中可以有“孔”(hole)。孔是逻辑上存在于数组中,但物理上不存在与内存中的那些数组项。在那些仅有少部分项被使用的数组中,孔可以大大减少内存空间的浪费。比如,我们要表示一个长度为10000的数组,它的最后一个项是字符串'a'。如果按照密集数组的做法,我们需要开辟10000个项的空间,有9999个项的空间都被浪费了。而如果按照稀疏数组的做法,稀疏数组只需要记录:“数组第10000个项的值为'a'”,这节省了很多内存空间。

JavaScript数组天生就是稀疏数组

js数组就是若干个下标(数字)与值之间的映射。从下标x到值y的映射表示:“数组第x个项的值为y”。这实际上就是上例中稀疏数组的记录方法。

在Chrome控制台的执行结果


如上图,如果你调用new Array(3),你得到的数组中只有一个属性length,记录了它的长度,但是没有任何下标(数字)与值之间的映射。这是一个只有3个孔的数组。

如上图,如果你继续执行a[1] = 'aaa',那么实际上是在这个稀疏数组中增加了一条从1到"aaa"之间的映射。

如上图,如果你继续执行a[10000]='bbb',也只不过是又增加了一条从10000到"bbb"之间的映射而已。length自动变为了10001,这符合我们的直觉。不存在映射关系,但又处在数组长度范围内的数组项,就是孔。此时,这个数组与长度为2的普通数组['aaa', 'bbb'],占用相同大小的内存空间。

JavaScript数组稀疏特性带来的“怪异现象”

slice会复制孔

var arr = [ 'a', , 'b' ]
// ["a", undefined × 1, "b"]
arr.slice(1,2)
// [undefined × 1]
arr.slice()
// ["a", undefined × 1, "b"]

forEach、every会跳过孔(不对孔调用回调函数)

var arr = [ 'a', , 'b' ]
// ["a", undefined × 1, "b"]
arr.forEach(function (x, i) { console.log(i+'.'+x) })
// 0.a
// 2.b
arr.every(function (x) { return x.length === 1 })
// true

map不对孔调用回调函数,但是孔会保留

arr.map(function (x,i) { return i+'.'+x })
// [ '0.a', undefined × 1, '2.b' ]

filter不对孔调用回调函数,但是孔会被过滤掉

arr.filter(function (x) { return true })
// [ 'a', 'b' ]

join会将孔转化为一个空字符串进行拼接,与undefined一样

arr.join('-')
// 'a--b'
[ 'a', undefined, 'b' ].join('-')
// 'a--b'

而其他所有的数组方法会正常对待孔,就像数组中真的存在这个“空位”一样:

var arr2 = arr.slice()
arr2.sort()
// [ 'a', 'b', undefined × 1 ]

初始化无孔数组的方法

因为数组中的孔会造成上述的那些“怪异现象”,所以我们有时希望初始化一个没有孔的数组。
比如我们希望初始化[0,1,2]这样的数组,但是我们无法通过new Array(3)与map方法得到:

var a1 = new Array(3)
// [undefined × 3]
a1.map(function (x, i) { return i })
// [undefined × 3]
// 因为map会跳过孔,所以实际上回调函数没有被调用过

a1有孔

正确的方法:

var a2 = Array.apply(null, Array(3))
// [undefined, undefined, undefined]
a2.map(function (x, i) { return i })
// [0, 1, 2]
// map的回调函数执行了3次

a2无孔

[undefined × 3]和[undefined, undefined, undefined],chrome控制台用这两种表示方式来区分孔和真正的undefined值!

从上面两幅图的对比可以看出,第一种方法没有构造出映射,只创造出了3个孔。而第二种方法创建出了真正的“从下标到值之间的映射”,映射的值为undefined。因此map不会跳过这些数组项。

Array.apply(null, Array(n))的原理

为什么var a2 = Array.apply(null, Array(3))能创造出无孔的数组呢?

我们将一个含有3个孔的数组作为第二个参数传递给apply,apply将利用这个数组来决定调用Array()的参数。

因为apply将数组中的孔视为undefined,所以Array调用的参数实际上为Array(undefined, undefined, undefined)。

又因为通过Array(a,b,c)这种方法调用Array会返回[a,b,c],所以Array(undefined, undefined, undefined)返回的是[undefined, undefined, undefined]。

参考资料

https://2ality.com/2013/11/initializing-arrays.html

https://2ality.com/2013/07/array-iteration-holes.html

https://2ality.com/2012/06/dense-arrays.html

https://2ality.com/2015/09/holes-arrays-es6.html

以上就是JavaScript稀疏数组与孔hole示例详解的详细内容,更多关于JavaScript稀疏数组与孔hole的资料请关注脚本之家其它相关文章!

相关文章

  • YUI Compressor压缩JavaScript原理及微优化

    YUI Compressor压缩JavaScript原理及微优化

    最近写一个jQuery插件,在最后完成优化时,对比发现压缩后文件比较大,就思考那些是可以被修改和优化的,发现压缩原理也有很大的空间可以学习
    2013-01-01
  • 浅谈几种常用的JS类定义方法

    浅谈几种常用的JS类定义方法

    下面小编就为大家带来一篇浅谈几种常用的JS类定义方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06
  • JS动态增加删除UL节点LI及相关内容示例

    JS动态增加删除UL节点LI及相关内容示例

    这篇文章主要介绍了JS如何动态增加删除UL节点LI及相关内容,需要的朋友可以参考下
    2014-05-05
  • bootstrap suggest下拉框使用详解

    bootstrap suggest下拉框使用详解

    这篇文章主要为大家详细介绍了bootstrap suggest js下拉框的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • 利用javascript实现的三种图片放大镜效果实例(附源码)

    利用javascript实现的三种图片放大镜效果实例(附源码)

    这篇文章主要介绍了利用javascript实现的几种放大镜效果,很实用一款漂亮的js图片放大镜特效,常见于电商网站上产品页,用来放大展示图片细节,很有实用性,推荐下载学习研究。文中提供了完整的源码供大家下载,需要的朋友可以参考借鉴,一起来看看吧。
    2017-01-01
  • GoJs的文本绘图模板TextBlock使用实例

    GoJs的文本绘图模板TextBlock使用实例

    这篇文章主要为大家介绍了GoJs的文本绘图模板TextBlock使用实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • Cropper.js进阶之固定宽高图片裁切实现示例

    Cropper.js进阶之固定宽高图片裁切实现示例

    这篇文章主要为大家介绍了Cropper.js进阶之固定宽高图片裁切实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 最简单的JavaScript图片轮播代码(两种方法)

    最简单的JavaScript图片轮播代码(两种方法)

    基于javascript代码实现最简单的图片轮播效果,非常简单,本文通过两种方式给大家介绍最简单的图片轮播,感兴趣的朋友一起学习吧
    2015-12-12
  • AutoJs4.4.1免费版快速接通vscode调试脚本的操作方法

    AutoJs4.4.1免费版快速接通vscode调试脚本的操作方法

    这篇文章主要介绍了AutoJs4.4.1免费版快速接通vscode进行调试脚本,首先下载AutoJs并安装,下载完成后,将2个apk文件拷贝到手机安装即可,接下来需要安装插件,本文分步骤给大家介绍的非常详细,需要的朋友可以参考下
    2022-10-10
  • js判断图片加载完成后获取图片实际宽高的方法

    js判断图片加载完成后获取图片实际宽高的方法

    这篇文章主要介绍了js判断图片加载完成后获取图片实际宽高的方法,涉及JavaScript图片加载及属性操作相关技巧,需要的朋友可以参考下
    2016-02-02

最新评论