随笔-深入学习ES6的Map和Set(底层数据结构层面

Map特性

1、键名可以是任意类型数据

JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

我觉得很尴尬,堂堂ES6专栏提出的两大新类型,两大新数据结构,它们对比Array和Object的差异只有这么一点。如果说只理解到这个层面的话,我相信大部分人在存储数据时,依旧会先想到Array和Object,而不是Set和Map。事实上确实如此,现在用的最多的依旧是Array和Object。

此时我们就需要深入学习Map和Set

对比Set和Array


首先我们需要理解Set如何实现元素不重复?Array能不能实现元素不重复?

我们先思考下如何实现Array存入元素不重复

class ArrayUnique {

constructor(){

this.container = []

}

has(ele) {

// 这里不使用indexOf和some,而使用原生for来让大家体验下数组查找值时的效率有多低,改进可以用二分

let flag = false;

for (let i = 0; i < this.container.length; i++) {

if(this.container[i] === ele || Object.is(ele, this.container[i])){

flag = true

break

}

}

return flag

}

add(ele) {

if(this.has(ele)) return false

this.container.push(ele)

return true

}

delete(ele) {

if(this.has(ele)) {

let index = this.container.indexOf(ele)

return this.container.splice(index,1)

}

return undefined

}

}

可以发现,Array只要稍加封装就能实现Set的特性。尴尬…

但是ArrayUnique有一种致命的缺点,低效。为什么说他低效呢,我们可以看看add功能实现,由于要保证add进的元素必须唯一,所以每次add前都需要判断该元素是否在数组中已存在,

而判断数组在元素中是否已存在,现有数组直接方法有indexOf,lastIndexOf,includes,间接方法有some,forEach,而我们需要知道这些方法的底层实现都是基于for循环遍历每一个数组元素来和要查找的元素进行对比,所以时间复杂度为O(n),导致数组基于值查找的低效性的原因是数组自身数据结构。

JS中Array的数据结构是啥呢?其实直白点说,Array也是Object。即Array也是键值对形式

可以发现:Array对象的键名就是整数值,键值就是添加进数组的元素,另外Array对象还有一个length属性来记录元素个数。

那么Array为什么要和Object区别开来呢?Object并不是很难实现一个Array形式的对象,比如类数组对象arguments,几乎具有了Array的所有特点,且可以借用Array原型上方法,所以几乎可以认为它们在形式上是一致的。

原因是:底层数据结构不同,数组的底层数据结构是一个线性表,即在内存上体现为一段连续的内存,假设内存被分为大小相同的块,一段连续的内存可以理解为一段紧挨着的多个内存块。我们知道数据存在内存中都是有内存地址的,而数据内存地址的计算和内存块的大小有关,

那么其实我们知道了内存块大小,数组起始位置内存地址,就可以获得数组中所有元素的起始内存地址了

比如创建一个数组长度为9的数组arr,arr的第一个元素位置是0x000,内存块大小是10(假设,真实计算很复杂),那么第一个元素的起始位置就是 0x000 + 0*10 第二个元素的起始位置就是 0x000 + 1*10,第三个元素的起始位置就是 0x000 + 2*10 ,最后一个元素的起始位置就是 0x000 + 8*10,而这个的0,1,2,…,8就是我们熟知的数组元素索引

arr[0],arr[1],arr[2],…,arr[8]

所以,说到现在,我们发现数组的优势是:根据索引号来查找数组元素,速度块,效率高。但是根据数组元素,查找数组元素的索引,那就没有捷径可言了,只能根据索引遍历出每一个数组元素,然后和要查找的数据元素进行对比,再优化一点就需要使用算法了,比如二分查找,排序后二分查找。

我们在回头看Array对象的整数值属性,你就不会觉得它是一个单纯的Object对象的属性了,首先它不是程序员设置的,而是数组底层根据内存块大小和数组对象在堆中起始内存地址计算得到的索引号。所以Array表面看上去是一个Object,平平无奇,但是底层内存层面上,人家有独到之处。

那么Set的底层实现也是数组吗?就像我们上面代码实现的那样?

答:肯定不是,如果是的话,那么Set就没有必要被创造出来了。

Set去重机制,准确来说是底层数据结构决定的,Set的底层数据结构是哈希表,什么是哈希表?

我们通常将哈希表称为数组升级版,或者说是数组“值”查询的救星。

数组在“值”查询上表现拙劣,性能不佳,而哈希表在”值“查询上表现良好,性能不错。

那么哈希表是如何实现”值“查询的呢?

哈希表在内存上,也是开辟一段连续内存用来存储数据,但是有别于数组,哈希表不会将元素按照添加顺序依次存入连续内存中,元素在内存中存储位置是由哈希算法计算得出的。

哈希算法:将元素值 和 哈希表长度 经过一种算法 计算出 元素 在哈希表中的存储位置

最简单的哈希算法,就是 元素值的哈希值 对 哈希表长度求模,得到模值,就是元素在哈希表中的存储位置

假设哈希表长度 5,现在要存入元素a,a的哈希值假设为123,那么123%5 = 3,那么a就存在哈希表的第3块内存上

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

算法

  1. 冒泡排序

  2. 选择排序

  3. 快速排序

  4. 二叉树查找: 最大值、最小值、固定值

  5. 二叉树遍历

  6. 二叉树的最大深度

  7. 给予链表中的任一节点,把它删除掉

  8. 链表倒叙

  9. 如何判断一个单链表有环

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

…(img-AusuXisL-1712592581170)]

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-MAQghA0Z-1712592581170)]

  • 27
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值