栈、堆、深浅拷贝深入理解(上)

140 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

两者都属于数据结构。

1.栈

栈是一种遵循 后进先出(LIFO) 原则的有序集合。

  新添加 和 待删除 的数据都保存在栈的同一端栈顶,另一端就是栈底。(先进后出,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据,最后一个数据被第一个读出来)

新元素靠近栈顶,旧元素靠近栈底。

  image.png

栈的优势: 存取速度比堆快; 缺点: 存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。-- 由操作系统自动分配释放,存放基本类型和复杂类型的地址。

堆的优势: 可以动态的分配内存大小; 缺点: 由于要在运行时动态分配内存,存取速度较慢。 -- 存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收,分配方式类似于链表。

 

1.1 存储栈(基本数据结构的存储)

堆在JavaScript中,数据类型分为:基本上局类型和引用数据类型。

基本数据类型: stringnumberbooleannullundefinedsymbol。

引用数据类型: FunctionObjectArrayDateRegExpMath

在内存中这几种数据类型存储在栈空间,按值访问。原型类型都存储在栈内存中,是大小固定并有序的。

 

1.2 执行栈(函数调用栈)

程序执行进入一个执行环境时,它的执行上下文就会被创建,并被推入执行栈中(入栈)。

程序执行完成时,它的执行上下文就会被销毁,并从栈顶被推出(出栈),控制权交由下一个执行上下文。

JavaScript中每一个可执行代码,在解释执行前,都会创建一个可执行上下文。按照可执行代码块可分为三种可执行上下文(全局、函数、Eval)。

 

1.3 栈溢出问题

a、栈大小限制;

不同浏览器对调用栈的大小是有限制,超出将出现栈溢出的问题。

下面代码可检验不同浏览器对调用栈的大小限制。

image.png

b、递归调用的栈溢出问题;

计算n的阶乘,最多需要保存n个调用记录,复杂度 O(n) 。如果超出限制,会出现栈溢出问题。

image.png

 

c、尾递归调用优化;

递归非常消耗内存,因同时保存成百上千个调用帧,容易发生‘栈溢出’错误,可以使用尾递归,由于只存在一个调用帧,所以不会发生‘栈溢出’。

image.png