var a = 20;var b = 'abc';var c = true;var d = { m: 20 }

因为JavaScript具有自动垃圾回收机制,所以对于前端开发来说,内存空间并不是一个经常被提及的概念,很容易被大家忽视。特别是很多不是计算机专业的朋友在进入到前端之后,会对内存空间的认知比较模糊,甚至有些人干脆就是一无所知。

当然也包括我自己。

在很长一段时间里认为内存空间的概念在JS的学习中并不是那么重要。可当我回过头来重新整理JS基础时,发现由于对它的模糊认知,导致了许多知识理解得并不明白。比如最基本的引用数据类型和引用传递到底是怎么回事儿?浅复制与深复制有什么不同?闭包到底是什么?等等。

因此,想要对JS的理解更加深刻,就必须对内存空间有一个清晰的认知。

在学习内存空间之前,我们需要对三种数据结构有一个清晰的理解。他们分别是堆(heap),栈(stack)与队列(queue)

一、栈数据结构

与C/C++不同,JavaScript中并没有严格意义上区分栈内存与堆内存。因此我们可以简单粗暴的理解为JavaScript的所有数据都保存在堆内存中。但是在某些场景,我们仍然需要基于栈数据结构的思维来实现一些功能,比如JavaScript的执行上下文(关于执行上下文我会在下一篇文章中总结)。执行上下文的执行顺序借用了栈数据结构的存取方式(也就是后面我们会经常提到的函数调用栈)。因此理解栈数据结构的原理与特点十分重要。

要简单理解栈的存取方式,我们可以通过类比乒乓球盒子来分析。如下图左侧。

乒乓球盒子与栈类比

这种乒乓球的存放方式与栈中存取数据的方式如出一辙。处于盒子中最顶层的乒乓球5,它一定是最后被放进去,但可以最先被使用。而我们想要使用底层的乒乓球1,就必须将上面的4个乒乓球取出来,让乒乓球1处于盒子顶层。这就是栈空间先进后出,后进先出的特点。图中已经详细的表明了栈空间的存储原理。

二、堆数据结构

堆数据结构是一种树状结构。它的存取数据的方式,则与书架与书非常相似。

书虽然也整齐的存放在书架上,但是我们只要知道书的名字,就可以很方便的取出我们想要的书,而不用像从乒乓球盒子里取乒乓一样,非得将上面的所有乒乓球拿出来才能取到中间的某一个乒乓球。好比在JSON格式的数据中,我们存储的key-value是可以无序的,因为顺序的不同并不影响我们的使用,我们只需要关心书的名字。

三、队列

在JavaScript中,理解队列数据结构的目的主要是为了清晰的明白事件循环(Event Loop)的机制到底是怎么回事。在后续的章节中我会详细分析事件循环机制。

队列是一种先进先出(FIFO)的数据结构。正如排队过安检一样,排在队伍前面的人一定是最先过检的人。用以下的图示可以清楚的理解队列的原理。

四、变量对象与基础数据类型

JavaScript的执行上下文生成之后,会创建一个叫做变量对象的特殊对象(具体会在下一篇文章与执行上下文一起总结),JavaScript的基础数据类型往往都会保存在变量对象中。

严格意义上来说,变量对象也是存放于堆内存中,但是由于变量对象的特殊职能,我们在理解时仍然需要将其与堆内存区分开来。

基础数据类型都是一些简单的数据段,JavaScript中有5种基础数据类型,分别是Undefined、Null、Boolean、Number、String。基础数据类型都是按值访问,我们可以直接操作保存在变量中的实际值。

ES6中新加了一种基础数据类型Symbol,可以先不用考虑他

五、引用数据类型与堆内存

与其他语言不同,JS的引用数据类型,比如数组Array,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JavaScript不允许直接访问堆内存中的数据,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以理解为保存在变量对象中的一个地址,该地址与堆内存的实际值相关联。

为了更好的搞懂变量对象与堆内存,我们可以结合以下例子与图解进行理解。

var a1 = 0;   // 变量对象var a2 = 'this is string'; // 变量对象var a3 = null; // 变量对象var b = { m: 20 }; // 变量b存在于变量对象中,{m: 20} 作为对象存在于堆内存中var c = [1, 2, 3]; // 变量c存在于变量对象中,[1, 2, 3] 作为对象存在于堆内存中

上例图解

当我们要访问堆内存中的引用数据类型时,实际上我们首先是从变量对象中获取了该对象的地址引用(或者地址指针),然后再从堆内存中取得我们需要的数据。

理解了JS的内存空间,我们就可以借助内存空间的特性来验证一下引用类型的一些特点。

在前端面试中我们常常会遇到这样一个类似的题目

// demo01.jsvar a = 20;var b = a;b = 30;// 这时a的值是多少?
// demo02.jsvar m = { a: 10, b: 20 }var n = m;n.a = 15;// 这时m.a的值是多少

在变量对象中的数据发生复制行为时,系统会自动为新的变量分配一个新值。var b = a执行之后,a与b虽然值都等于20,但是他们其实已经是相互独立互不影响的值了。具体如图。所以我们修改了b的值以后,a的值并不会发生变化。

demo01图解

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

因此当我改变n时,m也发生了变化。这就是引用类型的特性。

demo02图解

通过内存的角度来理解,是不是感觉要轻松很多?除此之外,我们还可以以此为基础,一步一步的理解JavaScript的执行上下文,作用域链,闭包,原型链等重要概念。其他的我会在以后的文章慢慢总结,敬请期待。

六、内存空间管理

因为JavaScript具有自动垃圾收集机制,所以我们在开发时好像不用关心内存的使用问题,内存的分配与回收都完全实现了自动管理。但是根据以往的开发经验,了解内存机制有助于自己清晰的认识到自己写的代码在执行过程中发生过什么,从而写出性能更加优秀的代码。

关心内存是一件非常重要的事情。

JavaScript的内存生命周期

  1. 分配你所需要的内存
  2. 使用分配到的内存(读、写)
  3. 不需要时将其释放、归还

为了便于理解,我们使用一个简单的例子来解释这个周期。

var a = 20;  // 在内存中给数值变量分配空间alert(a + 100);  // 使用内存a = null; // 使用完毕之后,释放内存空间

第一步和第二步我们都很好理解,JavaScript在定义变量时就完成了内存分配。第三步释放内存空间则是我们需要重点理解的一个点。

JavaScript有自动垃圾收集机制,那么这个自动垃圾收集机制的原理是什么呢?其实很简单,就是找出那些不再继续使用的值,然后释放其占用的内存。垃圾收集器会每隔固定的时间段就执行一次释放操作。

在JavaScript中,最常用的是通过标记清除的算法来找到哪些对象是不再继续使用的,因此a = null其实仅仅只是做了一个释放引用的操作,让 a 原本对应的值失去引用,脱离执行环境,这个值会在下一次垃圾收集器执行操作时被找到并释放。而在适当的时候解除引用,是为页面获得更好性能的一个重要方式。

需要注意的是,在局部作用域中,当函数执行完毕,局部变量也就没有存在的必要了,因此垃圾收集器很容易做出判断并回收。但是全局变量什么时候需要释放内存空间则很难判断,因此在我们的开发中,原则上应该避免使用全局变量。

建议收藏,不然刷着刷着就可能找不到了

有什么前端的问题欢迎私信我~期待你的到来。

我自己是一名从事了多年开发的web前端老程序员,目前辞职在做自己的web前端私人定制课程,今年我花了一个月整理了一份最适合2020年学习的web前端学习干货,各种框架都有整理,送给每一位前端小伙伴,想要获取的可以关注我的头条号并在后台私信我:前端,即可免费获取

前端保存之前输入的值_前端基础进阶(一):内存空间详细图解相关推荐

  1. jquery function_前端基础进阶(十三)详细图解jQuery扩展jQuery插件

    UI 鉴赏 早几年学习前端,大家都非常热衷于研究jQuery源码. 我至今还记得当初从jQuery源码中学到一星半点应用技巧的时候常会有一种发自内心的惊叹,"原来JavaScript居然可以 ...

  2. pyqt5获取文本框里输入的值_实战PyQt5: 060-输入对话框QInputDialog

    QInputDialog简介 在GUI应用中,经常有一些简单的输入信息需要交互,这时候可以使用QInputDialog来快速完成我们的工作,而不必创建一个新的对话框来实现. QInputDialog控 ...

  3. @requestparam map 接收前端的值_前端面试总结篇(初级)

    作为一个优秀的程序员,不仅仅可以解决工作的问题,还要不断的关注前端技术的发展,其中也包括了解最新的前端面试题,那么知识点来了,请接好 1. 你熟悉的es6 let.const.var的使用区别 let ...

  4. 前端怎么获取cookie的值_作为前端你必须要了解的安全性问题!

    前端技术不断发展,安全性的问题也越来越受到关注.作为前端工程师,保障网络安全也越来越重要. XSS攻击 XSS(Cross Site Scripting)跨站脚本攻击. 攻击者在网站上植入非法的htm ...

  5. 可为空的对象必须具有一个值_前端:这里有8个常见的JavaScript经典问题,总有一个你不会的...

    参考前端小智:https://juejin.im/post/5d2d146bf265da1b9163c5c9 1.了解函数提升 使用var关键字声明的变量在JavaScript中会被提升,并在内存中分 ...

  6. 前端怎么获取cookie的值_京东购物小程序cookie方案实践(附Demo)

    一.前言 早期为了解决"会话保持"的需求,社区中出现了「cookie 方案」并最终成为 W3C 标准:当某个网站登录成功后,客户端(浏览器)收到一个 cookie 标识(文本)并保 ...

  7. es6 获取对象的所有值_前端开发必备 - ES6 新特性之 Set和Map数据结构

    往期回顾: 前端开发必备 - ES6 新特性之 let 和 const 命令 前端开发必备 - ES6 新特性之 变量的解构赋值 前端开发必备 - ES6 新特性之 字符串的拓展 前端开发必备 - E ...

  8. js change事件 获取新值和旧值_前端总结(JS篇)

    JS 引入方式 1-内部js <script> </script> 2-外部引入 <script src="路径"> 注意不要写js代码 < ...

  9. 前端面试技巧和注意事项_前端面试百分之九十九过的技巧

    2020最全的前端面试指南,一个多月 1.8w 字的面试经验积累,凭借它最终成功入职大厂-- 今年的金三银四刚好赶上疫情,很多大公司都停止招聘甚至裁员,想跳槽的小伙伴被打的措手不及. 需求减少要求肯定 ...

  10. 前端md转html添加样式_前端文档站点搭建方案

    ? 这是第 46篇不掺水的原创,想要了解更多,请戳上方蓝色字体:政采云前端团队关注我们吧- 本文首发于政采云前端团队博客:前端文档站点搭建方案 https://www.zoo.team/article ...

最新文章

  1. 微软Citrix合作虚拟化联手对抗VMware
  2. java学习与总结:操作系统
  3. python 珠玑妙算
  4. [以太坊源代码分析] VI. 基于p2p的底层通信(上篇)
  5. PHP的自动加载__autoload spl_autoload_register
  6. 解决burpsuite无法对DVWA环境(本地环境)进行抓包
  7. ASP.NET2.0 XML系列(6): 使用XmlReaderSettings配置XmlReader的输出
  8. 《spring 2.0技术手册》的技术写作方式值得学习!
  9. 查看python版本和django版本
  10. 【语法】NSMutableArray可变数组
  11. 微信小程序一笔记账开发进度五
  12. QT制作动画收缩效果
  13. wms仓库管理系统中条形码管理的两大优势
  14. Matlab基本介绍
  15. P3110 [USACO14DEC]驮运Piggy Back-最短路,spfa
  16. 我在日本最大的房地产信息网站做重构
  17. springbootsecurity实现权限管理详细步骤
  18. OSPF(三)OSPF域内路由
  19. MATLAB 画图--图形属性设置
  20. security基于数据库的认证(二)

热门文章

  1. Redis集群方案介绍
  2. maven实战之我见一(maven初识)
  3. Ruby 常用的正则表达式1
  4. 转:shell脚本的一些注意事项
  5. 服务器无法分配系统页面缓冲池中的内存
  6. 关于#if NET1的一点小得
  7. plsql查询无结果集_何恺明一作,刷新7项检测分割任务,无监督预训练完胜有监督...
  8. 异常将上下文初始化事件发送到类的侦听器实例_Java虚拟机从入门到入土之JVM的类加载机制
  9. win开启审计功能_一项一项教你测等保2.0——Linux安全审计
  10. redis删除不存在的key会报错吗_Redis哈希类型