前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >比较JavaScript中的数据结构(数组与对象)

比较JavaScript中的数据结构(数组与对象)

作者头像
前端小智@大迁世界
发布于 2020-10-10 01:32:09
发布于 2020-10-10 01:32:09
5.5K00
代码可运行
举报
文章被收录于专栏:终身学习者终身学习者
运行总次数:0
代码可运行

大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】

在编程中,如果你想继续深入,数据结构是我们必须要懂的一块, 学习/理解数据结构的动机可能会有所不同,一方面可能是为了面试,一方面可能单单是为了提高自己的技能或者是项目需要。无论动机是什么,如果不知道什么是数组结构及何时使用应用字们,那学数据结构是一项繁琐且无趣的过程 ?

这篇文章讨论了什么时候使用它们。在本文中,我们将学习数组和对象。我们将尝试通过使用Big O notation来理解何时选择一种数据结构。

Big O notation 大零符号一般用于描述算法的复杂程度,比如执行的时间或占用内存(磁盘)的空间等,特指最坏时的情形。

数组

数组是使用最广泛的数据结构之一。 数组中的数据以有序的方式进行结构化,即数组中的第一个元素存储在索引0中,第二个元素存储在索引1中,依此类推。 JavaScript为我们提供了一些内置的数据结构,数组就是其中之一 ?

在JavaScript中,定义数组最简单的方法是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let arr = []

上面的代码行创建了一个动态数组(长度未知),为了了解如何将数组的元素存储在内存中,我们来看一个示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let arr = ['John', 'Lily', 'William', 'Cindy']

在上面的示例中,我们创建一个包含一些人名的数组。 内存中的名称按以下方式存储:

为了理解数组是如何工作的,我们需要执行一些操作:

添加元素:

在JavaScript数组中,我们有不同方式在数组结尾,开关以及特定索引处添加元素。

在数组的末尾添加一个元素:

JavaScript 中的数组有一个默认属性 length,它表示数组的长度。除了length属性外,JS还提供了 push() 方法。 使用这个方法,我们可以直接在最后添加一个元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
arr.push('Jake')

那么这个命令的复杂度是多少呢?我们知道,在默认情况下,JS提供了length属性,push()相当于使用以下命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
arr[arr.length - 1] = 'Jake'

因为我们总是可以访问数组的长度属性,所以无论数组有多大,在末尾添加一个元素的复杂度总是O(1) ?。

在数组的开头添加一个元素:

对于此操作,JavaScript提供了一个称为unshift()的默认方法,此方法将元素添加到数组的开头。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let arr = ['John', 'Lily', 'William', 'Cindy']
arr.unshift('Robert')
console.log(arr) // [ 'Robert', 'John', 'Lily', 'William', 'Cindy' ]

unshift方法复杂度好像和push方法的复杂度一样:O(1),因为我们只是在前面添加一个元素。 事实并非如此,让我们看一下使用unshift方法时会发生什么:

在上图中,当我们使用unshift方法时,所有元素的索引应该增加1。这里我们的数组个数比较少,看不出存在的问题。想象一下使用一个相当长的数组,然后,使用unshift这样的方法会导致延迟,因为我们必须移动数组中每个元素的索引。因此,unshift操作的复杂度为O(n) ?。

如果要处理较大长度的数组,请明智地使用unshift方法。在特定索引处添加元素,我们可以 splice() 方法,它的语法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
splice(startingIndex, deleteCount, elementToBeInserted)

因为我们要添加一个元素,所以deleteCount将为0。例如, 我们想要在数组索引为2的地方新加一个元素,可以这么用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let arr = ['John', 'Lily', 'William', 'Cindy']
arr.splice(2, 0, 'Janice')
console.log(arr)
// [ 'John', 'Lily', 'Janice', 'William', 'Cindy' ]

你觉得这个操作的复杂性是多少?在上面的操作中,我们在索引2处添加了元素,因此,在索引2之后的所有后续元素都必须增加或移动1(包括之前在索引2处的元素)。

可以观察到,我们不是在移动或递增所有元素的索引,而是在索引2之后递增元素的索引。这是否意味着该操作的复杂度为 `O(n/2)? 不是 ?。 根据Big O规则,常量可以从复杂性中删除,而且,我们应该考虑最坏的情况。 因此,该操作的复杂度为O(n) ?。

删除元素:

就像添加元素一样,删除元素可以在不同的位置完成,在末尾、开始和特定索引处。

在数组的末尾删除一个元素:

push( )一样,JavaScript提供了一个默认方法pop(),用于删除/删除数组末尾的元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let arr = ['Janice', 'Gillian', 'Harvey', 'Tom']
arr.pop()
console.log(arr)
// [ 'Janice', 'Gillian', 'Harvey' ]

arr.pop()
console.log(arr)
// [ 'Janice', 'Gillian' ]

该操作的复杂度为O(1)。因为,无论数组有多大,删除最后一个元素都不需要改变数组中任何元素的索引。

在数组的开头删除一个元素:

JavaScript 提供了一个默认方法shift() 的默认方法,此方法删除数组的第一个元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let arr = ['John', 'Lily','William','Cindy']
arr.shift()
console.log(arr) // ['Lily','William','Cindy']
arr.shift()
console.log(arr);// ['William','Cindy'] 

从上面我们很容易可以看出 shift()操作的复杂度为O(n) ,因为删除第一个元素后,我们必须将所有元素的索引移位或减量1

在特定索引处删除:

对于此操作,我们再次使用splice()方法,不过这一次,我们只使用前两个参数,因为我们不打算在该索引处添加新元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let arr = ['Apple', 'Orange', 'Pear', 'Banana','Watermelon']
arr.splice(2,1)
console.log(arr) // ['Apple', 'Orange', 'Banana','Watermelon']

与用splice添加元素操作类似,在此操作中,我们将递减或移动索引2之后的元素索引,所以复杂度是O(n)

查找元素:

查找只是访问数组的一个元素,我们可以通过使用方括号符号(例如: arr[4])来访问数组的元素。

你认为这个操作的复杂性是什么? 我们通过一个例子来演示一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let fruits = ['Apple', 'Orange', 'Pear']

前面我们已经看到,数组的所有元素都按顺序存储,并且始终分组在一起。 因此,如果执行fruits[1],它将告诉计算机找到名为fruits的数组并获取第二个元素(数组从索引0开始)。

由于它们是按顺序存储的,因此计算机不必查看整个内存即可找到该元素,因为所有元素按顺序分组在一起,因此它可以直接在fruits数组内部查看。 因此,数组中的查找操作的复杂度为 O(1)

我们已经完成了对数组的基本操作,我们先来小结一下什么时候可以使用数组:

当你要执行像push()(在末尾添加元素)和pop()(从末尾删除元素)这样的操作时,数组是合适的,因为这些操作的复杂度是O(1)

除此之外,查找操作可以在数组中非常快地执行。

使用数组时,执行诸如在特定索引处或在开头添加/删除元素之类的操作可能会非常慢,因为它们的复杂度为O(n)

对象

像数组一样,对象也是最常用的数据结构之一。 对象是一种哈希表,允许我们存储键值对,而不是像在数组中看到的那样将值存储在编号索引处。

定义对象的最简单方法是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let obj1 = {}

事例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let student = {
    name: 'Vivek',
    age: 13,
    class: 8
}

来看一下上面的对象是如何存储在内存中的:

可以看到,对象的键-值对是随机存储的,不像数组中所有元素都存储在一起。这也是数组与对象的主要区别,在对象中,键-值对随机存储在内存中。

我们还看到有一个哈希函数(hash function)。 那么这个哈希函数做什么呢? 哈希函数从对象中获取每个键,并生成一个哈希值,然后将此哈希值转换为地址空间,在该地址空间中存储键值对。

例如,如果我们向学生对象添加以下键值对:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
student.rollNumber = 322

rollNumber键通过哈希函数,然后转换为存储键和值的地址空间。现在我们已经对对象如何存储在内存有了基本的了解,让我们来执行一些操作。

添加

对于对象,我们没有单独的方法将元素添加到前面或后面,因为所有的键-值对都是随机存储的。只有一个操作是向对象添加一个新的键值对。

事例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
student.parentName = 'Narendra Singh Bisht'

从上图中我们可以得出结论,这个操作的复杂性总是O(1),因为我们不需要改变任何索引或操作对象本身,我们可以直接添加一个键-值对,它被存储在一个随机的地址空间。

删除

与添加元素一样,对象的删除操作非常简单,复杂度为O(1)。因为,我们不必在删除时更改或操作对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
delete student.parentName
查找

查找的复杂度O(1) ,因为在这里,我们也只是借助键来访问值。访问对象中的值的一种方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
student.class

在对象中添加,删除和查找的复杂度为O(1)???那么我们可以得出结论,我们应该每次都使用对象而不是数组吗? 答案是不。 尽管对象很棒,但是在使用对象时需要考虑一些小的情况,就是哈希碰撞(Hash Collisions)。 在使用对象时,并非始终应处理此情况,但了解该情况有助于我们更好地理解对象。

那么什么是哈希碰撞?

当我们定义一个对象时,我们的计算机会在内存中为该对象分配一些空间。 我们需要记住,我们内存中的空间是有限的,因此有可能两个或更多键值对可能具有相同的地址空间,这种情况称为哈希碰撞。 为了更好地理解它,我们看一个例子:

假设为下面的对象分配了5块空间

我们观察到两个键值对存储在相同的地址空间中。 怎么会这样?当哈希函数返回一个哈希值,该哈希值转换为多个键的相同地址空间时,就会发生这种情况。 因此,多个 key 被映射到相同的地址空间。 由于哈希碰撞,添加和访问对象值的复杂度为O(n) ,因为要访问特定值,我们可能必须遍历各种键值对。

哈希碰撞并不是我们每次使用对象时都需要处理的东西。 这只是一个特殊的情况,该情况也说明了对象不是完美的数据结构。

除了*哈希碰撞,使用对象时还必须注意另一种情况。 JS 为我们提供了一个内置的keys()方法,用于遍历对象的键。

我们可以将此方法应用于任何对象,例如:object1.keys()keys()方法遍历对象并返回所有键。 尽管此方法看起来很简单,但我们需要了解对象中的键值对是随机存储在内存中的,因此,遍历对象的过程变得较慢,这与遍历按顺序将它们分组在一起的数组不同。

总结一下,当我们想执行诸如添加,删除和访问元素之类的操作时,可以使用对象,但是在使用对象时,我们需要谨慎地遍历对象,因为这可能很耗时。 除了进行遍历外,我们还应该理解,有时由于哈希碰撞,访问对象操作的复杂度可能会变为O(n)


代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
重新介绍 JavaScript(JS全面系列教程)
为什么会有这一篇“重新介绍”呢?因为 JavaScript 堪称世界上被人误解最深的编程语言。虽然常被嘲为“玩具语言”,但在它看似简洁的外衣下,还隐藏着强大的语言特性。 JavaScript 目前广泛应用于众多知名应用中,对于网页和移动开发者来说,深入理解 JavaScript 就尤有必要。
ihoey
2018/10/31
1.7K0
深入理解JavaScript面向对象的程序设计(一)——对象的创建
类似Java等面向对象语言中创建对象的语法,在 JavaScript中可以通过执行 new操作符后跟要创建的对象类型的名称来创建。JavaScript中通过如下方式可以创建一个Object对象:
CherishTheYouth
2020/11/12
4380
深入理解JavaScript面向对象的程序设计(一)——对象的创建
第67天:面向对象的声明、封装
一、声明对象 有两种声明对象的方式. 1、var obj = new Object(); 但是我们更提倡用第二种方法: 字面量式声明对象  2、var obj  = {}; 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 9 </body> 10 </html> 11 <script> 1
半指温柔乐
2018/09/11
4730
JS篇(009)-javascript 对象的几种创建方式
这行代码创建了 Object 引用类型的一个新实例,然后把实例保存在变量 Person 中。 第二种:使用对象字面量表示法
齐丶先丶森
2022/05/12
1.6K0
JavaScript之JS的数据类型
JavaScript一共有6中数据类型: 基本数据类型(5):字符串(String)、数字(Number)、布尔(Boolean)、数组(Array)、空(Null)、未定义(Undefined) 复杂数据类型(1):对象(Object) 注意:Array、Date、Math、Error Set(ES6).....都是属于Object中
用户1195962
2018/09/13
1.4K0
JavaScript之JS的数据类型
javascript高级程序设计(4-5)章笔记
版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/article/details/51234909
空空云
2018/09/27
4480
前端学习(32)~js学习(九):对象简介和对象的基本操作
对象的作用是:封装信息。比如Student类里可以封装学生的姓名、年龄、成绩等。
Vincent-yuan
2020/03/18
6530
[JavaScript] 数组与对象详解
对象是键值对的集合,每个键值对称为对象的一个 属性。键是字符串或符号,值可以是任意类型。
DevKevin
2025/01/23
540
前端学习(37)~js学习(十四):对象的创建
第一次看到这种工厂模式时,你可能会觉得陌生。如果简化一下,可以写成下面这种形式,更容易理解:(也就是,利用new Object创建对象)
Vincent-yuan
2020/03/18
1.7K0
JS中的面向对象、原型、原型链、继承总结大全
补充: js中说一切都是对象,是不完全的,在js中6种数据类型(Undefined,Null,Number,Boolean,String,Object)中,前五种是基本数据类型,是原始值类型,这些值是在底层实现的,他们不是object,所以没有原型,没有构造函数,所以并不是像创建对象那样通过构造函数创建的实例。关于对象属性类型的介绍就不介绍了。
疯狂的技术宅
2019/03/27
1.4K0
JS中的面向对象、原型、原型链、继承总结大全
javascript
1.创建Object实例两种方式。 var obj=new Object(); obj.name='zhangsan'; 第二种方式:使用对象字面量表示法。 var person={ name:'zhangsan', age:12 } function display(info){ var outopt=""; if(typeof info.name== "string"){ output += "Name:"+info.name+"\n"; } if(typeof info.age=="number"
wangxl
2018/03/07
7830
JavaScript对象和数组
学习要点: 1.Object类型 2.Array类型 3.对象中的方法 什么是对象,其实就是一种类型,即引用类型。而对象的值就是引用类型的实例。 一.Object类型 到目前为止,我们使用的引用类型最多的可能就是Object类型了。虽然Object的实例不具备多少功能,但对于在应用程序中的存储和传输数据而言,它确实是非常理想的选择。 创建Object类型有两种。一种是使用new运算符,一种是字面量表示法。 1.使用new运算符创建Object var box = new Object();
汤高
2018/01/11
1.8K0
从零开始学 Web 之 JavaScript(五)面向对象
(创建对象的最简单方式就是创建一个 Object 的实例,然后再为它添加属性和方法。)
Daotin
2018/08/31
4780
JavaScript 对象与 Hash 表
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
李振
2021/11/26
2K0
JavaScript 对象与 Hash 表
你要的对象都在这啦|how to create Object in JavaScript?
小伙伴们,大家好,今天我们来说一下Javascript中创建对象的几种方式,请看文章。
石璞东
2020/10/28
3310
你要的对象都在这啦|how to create Object in JavaScript?
JavaScript小技能:变量
如果我们没有变量,我们就不得不写大量的代码去枚举和检查输入的名字,然后去显示它们,这样做显然是低效率和不可行的 。
公众号iOS逆向
2022/08/22
7080
JavaScript小技能:变量
浅谈JavaScript的面向对象程序设计(一)
  面向对象的语言有一个标志,他们都有类的概念,通过类可以创建多个具有相同属性和方法的对象。但是JavaScript中没有类的概念,因此JavaScript与其他的面向对象语言还是有一定区别的。JavaScript把对象定义为无序属性的集合,其属性可以包含基本值、对象或者函数。对象的每个属性或者方法都有一个名字,而每个名字都映射到一个值。所有我把JavaScript的对象看成一组无序的键值对。 对象是什么   以前曾介绍过对象的创建,建立对象最简单的方式就是建立Object对象的一个实例,再为他添加属性和方
水击三千
2018/02/27
7360
JavaScript——对象
例如:一本书、一辆汽车、一个人都可以是“对象”,而一个数据库、一个网页、一个与远程服务器的连接也可以是“对象”。
岳泽以
2022/10/26
5640
JavaScript——对象
JavaScript学习总结(四)——this、原型链、javascript面向对象
根据题目要求,对给定的文章进行摘要总结。
张果
2018/01/04
1.5K0
JavaScript学习总结(四)——this、原型链、javascript面向对象
JavaScript入门
(53条消息) python基础:布尔运算和四个语句_sayhi:的博客-CSDN博客_python布尔运算
Breeze.
2022/06/27
6690
JavaScript入门
推荐阅读
相关推荐
重新介绍 JavaScript(JS全面系列教程)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验