亚博全站

contact us
亚博全站
邮政编码:201613
服务电话:400-0645-900
021-67640000
销售联系:021-67648132
企业传真:021-67648130
电子邮件:sales@c-ga.com
官方网址:www.jsdsqc.com

首页 > 产品中心 > 堆高设备

JavaScript中的堆栈 stack heap 队列 数据结构学习 最全图片讲解
正品保障售后无忧增值税发票

发布时间:2022-05-26 22:20:17 来源:亚博全站 作者:亚博全站手机版

  如下图所示:栈内存中存放的只是该对象的访问地址, 在堆内存中为这个值分配空间 。 由于这种值得大小不固定,因此不能把它们保存到栈内存中。但内存地址大小的固定的,因此可以将内存地址保存在栈内存中。 这样,当查询引用类型的变量时, 先从栈中读取内存地址, 然后再通过地址找到堆中的值。

  当我们看到一个变量类型是已知的,就分配在栈里面,比如INT,Double等。其他未知的类型,比如自定义的类型,因为系统不知道需要多大,所以程序自己申请,这样就分配在堆里面。

  上方例子得知,当我改变arr2中的数据时,arr1中数据也发生了变化,当改变str1的数据值时,arr1却没有发生改变。为什么?这就是传值与传址的区别。

  因为arr1是数组,属于引用类型,所以它赋予给arr2的时候传的是栈中的地址(相当于新建了一个不同名“指针”),而不是堆内存中的对象的值。str1得到的是一个基本类型的赋值,因此,str1仅仅是从arr1堆内存中获取了一个数值,并直接保存在栈中。arr1、arr2都指向同一块堆内存,arr2修改的堆内存的时候,也就会影响到arr1,str1是直接在栈中修改,并且不能影响到arr1堆内存中的数据。

  基本数据类型:基本数据类型是指保存在栈内存中的简单数据段。访问方式是按值访问。

  基本类型变量的复制:从一个变量向一个变量复制时,会在栈中创建一个新值,然后把值复制到为新变量分配的位置上。

  当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈存里,随着方法的执行结束,这个方法的栈存也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;

  当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本开销较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。

  demo1中在变量对象中的数据发生复制行为时,系统会自动为新的变量分配一个新值。var b = a执行之后,b虽然重新赋值为2,但是他们其实已经是相互独立互不影响的值了。

  demo2中我们通过var n = m执行一次复制引用类型的操作。引用类型的复制同样也会为新的变量自动分配一个新的值保存在变量对象中,但不同的是,这个新的值,仅仅只是引用类型的一个地址指针。当地址指针相同时,尽管他们相互独立,但是在变量对象中访问到的具体对象实际上是同一个。因此当我改变n时,m也发生了变化。这就是引用类型的特性。

  要了解JavaScript数组的堆栈和队列方法的操作,需要先对堆栈和队列基础知识有所了解。在继续看后面的内容之前,我们先简单地了解一下堆栈和队列的概念。

  栈和队列都是动态的集合,在栈中,可以去掉的元素是最近插入的那一个。栈道实现了后进先出。在队列中,可以去掉的元素总是在集合中存在的时间最长的那一个。队列实现了先进先出的策略。

  栈是一种LIFO(Last-In-First-Out,后进先出)的数据结构,也就是最新添加的项最早被移除。而栈中项的插入(叫做推入)和移除(叫做弹出),只发生在一个位置——栈的顶部。

  最开始栈中不含有任何数据,叫做空栈,此时栈顶就是栈底。然后数据从栈顶进入,栈顶栈底分离,整个栈的当前容量变大。数据出栈时从栈顶弹出,栈顶下移,整个栈的当前容量变小。

  比如说,我们在一个箱子中放了很多本书,如果你要拿出第二本书,那么你要先把第一本书拿出来,才能拿第二本书出来;拿出第二本书之后,再把第一本书放进去。

  ECMAScript为数组专门提供了 push() 和 pop() 方法,以便实现类似的行为。 push() 方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。而 pop() 方法则从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。

  栈数据结构的访问规则是LIFO(后进先出),而队列数据结构的访问规则是FIFO(Fist-In-First-Out,先进先出)。队列在列表的末端添加项,从列表的前端移除项。如下图所示:

  入队列操作其实就是在队尾追加一个元素,不需要任何移动,时间复杂度为O(1)。出队列则不同,因为我们已经架设下标为0的位置是队列的队头,因此每次出队列操作所有元素都要向前移动。如下图所示:

  ECMAScript为数组专门提供了 shift() 和 unshift() 方法,以便实现类似队列的行为。由于 push() 是向数组末端添加数组项的方法,因此要模拟队列只需一个从数组前端取得数组项的方法。实现这一操作的数组方法就是 shift() ,它能够移除数组中的第一个项并返回该项,同时将数组长度减1。

  顾名思义, unshift() 与 shift() 的用途相反:它能在数组前端添加任意个数组项并返回新数组的长度。因此,同时使用 unshift() 和 pop() 方法,可以从相反的方向来模拟队列,即在数组的前端添加数组项,从数组末端移除数组项。

  push()方法可以接收任意数量的参数,把它们逐个添加到数组的末尾,并返回修改后数组的长度。如:

  pop()方法刚好和push()方法相反。pop()方法删除数组的最后一个元素,把数组的长度减1,并且返回它被删除元素的值,如果数组变为空,则该方法不改变数组,返回undefine值。如下代码演示:

  unshift()方法是向数组的开头添加一个或多个元素,并且返回新的长度。

  shift()方法和unshift()方法恰恰相反。该方法用于把数组的第一个元素从其中删除,并返回被删除的值。如果数组是空的,shift()方法将不进行任何操作,返回undefined的值。

  了解这几种方法之后,我们就可以将它们结合起来,轻松的实现类似栈和队列的行为。

  将shift()和push()方法结合在一起,可以像使用队列一样使用数组。即在数组的后端添加项,从数组的前端移除项:

  除此之外,还可以同时使用unshift()和pop()方法,从相反的方向来模拟队列,即在数组的前端添加项,从数组的后端移除项。如下面的示例所示:

  Array的push()与unshift()方法都能给当前数组添加元素,不同的是,push()是在末尾添加,而unshift()则是在开头添加,从原理就可以知道,unshift()的效率是较低的。原因是,它每添加一个元素,都要把现有元素往下移一个位置。但到底效率差异有多大呢?下面来简单测试一下。

  这段代码分别执行了100000次push()和unshift()操作,在chrome浏览器运行一次,得到的结果如下图所示:

  可见,unshift()比push()要慢差不多100倍!因此,平时还是要慎用unshift(),特别是对大数组。那如果一定要达到unshift()的效果,可以借助于Array的reverse()方法,Array的reverse()的方法能够把一个数组反转。先把要放进数组的元素用push()添加,再执行一次reverse(),就达到了unshift()的效果。比如:

  //Array有一个叫做reverse的方法,能够把一个数组反转。先把要放进数组的元素用push添加,再执行一次reverse,就达到了unshift的效果

  本文主要介绍了JavaScript数组的push()、pop()、shift()和unshift()方法。并且如何通过组合这几种方法实现类似栈和队例的行为。

  splice有3个参数,它也可以用来替换/删除/添加数组内某一个或者几个值

  index:数组开始下标 len: 替换/删除的长度 item:替换的值,删除操作的话 item为空

  2:delete delete删除掉数组中的元素后,会把该下标出的值置为undefined,数组的长度不会变



上一篇:宗申动力:公司目前的氢燃料电池适用于叉车、摩托车等终端尚未在无人机、通航飞机等终端平台使用
下一篇:云南烟叶复烤有限责任公司2022年专用车辆(电动托盘搬运车、电动堆高机)采购项目中标结果公告