复杂值vs原始值内存空间

2024-06-19 23:38
文章标签 vs 原始 内存空间 复杂

本文主要是介绍复杂值vs原始值内存空间,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在前面

     最近在读《JavaScript启示录》,这本书不是JavaScript的详尽的参考指南,但是把对象作为了解JavaScript的透镜,受益匪浅。

     那么我们先来聊一下JavaScript的原始值(值类型)以及复杂值(引用类型),以及他们在内存空间中的存储,关于他们你可能不清楚的一些事:

     我们先通过一个经典的面试题类型(并不是原题,我即兴发挥)引出我们今天的主题:

  1140602-20170913231017985-195870781.png

  1140602-20170913231023453-1314449337.png

我们已经看出他们的差别,在图一:我们让b = a,改变b的值,发现a并没有改变。在图二:我们让d = c,通过d.name改变对象的name属性,发现c.name也变化了。

事实上,原始值存储在栈内存中,按值来访问。复杂值(引用类型)在堆内存里面,按引用地址访问;然后我们会想到局部变量和全局变量在内存中的存储:下面是我在一个群中给一个同行的回答(前辈们莫见笑)

  1140602-20170914002628500-1790918000.png

 

下面会具体介绍复杂值、原始值以及他们的一些特性与内存空间:

  1140602-20170914001718766-587587788.png

  1、原始值是非对象

我们老生常谈的JavaScript五大基本的数据类型,null、undefined、number、string、boolean都被视为原始值,因为他们是不可细化的,本身是简单的,不能表示由其他的值组成的值。

      这里需要注意的是:与使用字面量语法创建相反,在使用new关键字创建的String,Number,或Boolean值时,创建的实际上是一个复杂对象,此时已不在是原始值

  a、下面对原始值和原生JavaScript对象之间的差异进行了比较:

  1140602-20170913231146563-337622010.png

需要注意没有使用new关键词,从构造函数返回的字符、数字、布尔值 对比 使用字面量方法所创建的仍然不是对象。

  b、我们在来对比一下使用new关键字创建的构造函数:

  1140602-20170913231156532-810228402.png

除了new出来的Function()对象返回的是function,其他都是object,其实在JavaScript中对函数定义非常高,因此在引用类型中,typeof能检测出函数的详细类型。

上述代码可以告诉我们:原始值不是对象,原始值的特殊之处是用于表示简单值;

  2、原始值的赋值,存储,比较方式

  a、原始值在“ 面值(face value)”中的存储和操作,理解这一点非常重要,因为原始值是真实值的复制

  1140602-20170913231311875-1631648021.png

这里的重点是,原始值是作为不可细化的值进行存储和操作的,引用他们会转移其值:这里的意思也就是原始值(值类型)在内存中每一个值都会存储在对应的变量的中去,也就是一个真实值的”复制”

  b、原始值的比较采用值比较

我们通过比较原始值来确定其值在字面上是否相同

通过下面的代码来理解“值比较“的概念,并将它与复杂数字进行比较:

  1140602-20170913231319063-1160059969.png

 

这里的重点是,在进行比较时,原始值会去检查表示的值是否相等,这里我们要特别和复杂值进行比较(因为复杂值不会去比较值是否相等,而是比较引用地址是否相同)

3、原始值(String,Number,Boolean)在被用做对象时就像对象

null和undefined都是非常简单的值,它们不需要构造函数,也没有new操作为自己创建JavaScript值(可以把他们当做操作符来使用即可)

原始值被当做构造函数创建的一个对象来使用时(注意不使用new),JavaScript会把其转化为一个对象,以便可以使用对象的特性(如方法),而抛弃对象的性质,并将它返回到原始值。

   1140602-20170913231332547-1514482111.png

上述实例代码,所有的原始值(除null、undefined)都被转化为对象,以便充分利用toString()方法一旦调用和返回改方法,对象就会被转换成对象值。这样我相信我们能很好的理解标题了

4、复杂值(复合对象、引用类型)

本质上,复杂对象其在内存中的大小是未知的,因为复杂对象可以包含任何值:

下面通过字面量的方法创建一个对象和数组

  1140602-20170913231400032-907471302.png

相比简单的原始值,原始值不能表示复杂值,而复杂值可以封装任意的JavaScript值

5、如何存储或复制复杂值

复杂值是通过引用来进行存储和操作的,这就回到了开始那个问题的图二,理解这一点非常重要。创建一个包含复杂对象的变量时,其值是内存中的一个引用地址。引用一个复杂对象时,使用它的名称(即变量或对象属性)通过内存中的引用地址获取对象值。当我们试图复制一个复杂值的时候,理解这就非常重要了。复杂值复制的过程、其实并不是复制对象,更多的是像复制对象的地址

  1140602-20170913231431438-2039701940.png

所以就像上面说过的,复制的是内存堆栈中对象的地址或者引用

6、复杂对象比较采用引用比较

也就是说:复杂对象只有在引用相同的对象(即有相同的引用地址)时才相等

   1140602-20170913231437907-916859876.png

我相信我们已经理解:指向内存中复杂对象的变量,只有在引用相同对的‘地址’的情况下才是相等的,相反,两个单独创建的对象、即使具有相同的类型并拥有完全相同的属性,他们也是不相等的

7、复杂对象具有动态属性

通过这一点,我们可以根据需求为复杂对象有任意多个引用。

  1140602-20170913233107141-918248776.png

上述代码,objA、pointer1、pointer2都引用了内存中的同一对象

  1140602-20170913233609360-1143644352.png

【emoji罒ω罒】这三个每次调用对象的方法都会叫他‘一个人’

  1140602-20170914001921625-1701844322.png

复杂对象支持动态对象属性,因为我们可以定义对象,然后创建引用,在更新对象、并且所有指向该对象的变量都会’获得’更新.

8、动态属性支持异变对象

复杂对象是由动态属性构成的,这一点非常重要,这使得用户自定义对象和大多数原生对象产生突变。通过增加原生对象、来改变JavaScript本身的原生预配置特性:

下面我们在原生构造函数上存储属性,并在原型对象上,向原生对象添加新方法:

  1140602-20170913231534250-51088985.png

所以我们明白,JavaScript的对象是动态的,这使得JavaScript对象是可变的。通过自定义我们改变了原生内部的运行机制,你会获得一个自定义版本的JavaScript来处理程序,但是使用一定要谨慎。

9、两个存储空间:栈&&堆

 我们前面也提到了存储空间,在程序运行时,有两个存储空间可用,一个是栈,归属进程本身的;另一个是堆,所有进程共用的

     然后就很好理解了,因为局部变量声明在函数周期内部,在函数结束时其生命周期也就结束了,其存储空间位于栈中,当进入函数时,会根据函数内部需求,在栈申请一段内存空间,供局部变量使用。当局部变量生命周期结束后(该函数结束),在栈上释放。

     由于进程栈的空间是有限的,所以1)要避免申请占用空间较大的局部变量,2)避免函数嵌套层数过多,这些都可能引起栈空间不够导致程序崩溃。

   关于数据结构中栈和堆,后面还会进一步的学习总结,比如管理方式、申请大小、碎片问题、分配方式、分配效率...

 写在后面

相信到这里我们对js中的原始值、复杂值、以及他们的特性、在内存中的存储有了比较深入的理解,那么让我们开始准确我们的JavaScript世界观系列,因为我从高中毕业后接触前端,对原生的热爱程度远远大于jQuery等类库。如果想实现JavaScript类库或者框架,应该打开“引擎盖”看看,了解发动机的情况。

  1140602-20170914001223328-748175267.png

这篇关于复杂值vs原始值内存空间的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1076483

相关文章

java poi实现Excel多级表头导出方式(多级表头,复杂表头)

《javapoi实现Excel多级表头导出方式(多级表头,复杂表头)》文章介绍了使用javapoi库实现Excel多级表头导出的方法,通过主代码、合并单元格、设置表头单元格宽度、填充数据、web下载... 目录Java poi实现Excel多级表头导出(多级表头,复杂表头)上代码1.主代码2.合并单元格3.

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

最近心情有点复杂:论心态

一月一次的彷徨又占据了整个身心;彷徨源至不自信;而不自信则是感觉自己的价值没有很好的实现亦或者说是自己不认可自己的目前的生活和状态吧。 我始终相信一句话:任何人的生活形态完全是由自己决定的;外在的总归不能直达一个人的内心深处。所以少年 为了自己想要的生活 多坚持努力吧、不为别人只为自己心中的那一丝执着。 由此我看到了一个故事: 一个心情烦躁的人去拜访禅师。他问禅师:我这辈子就这么注定了吗?您

VS Code 调试go程序的相关配置说明

用 VS code 调试Go程序需要在.vscode/launch.json文件中增加如下配置:  // launch.json{// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information,

操作系统是怎么为不同的程序分配所需的内存空间的

操作系统为不同的程序分配内存空间的过程涉及多个关键步骤,确保每个程序都有其所需的内存资源,同时避免程序之间的冲突。以下是操作系统如何为程序分配内存空间的详细过程: 1. 内存管理的基础概念 虚拟内存:现代操作系统使用虚拟内存机制来为程序提供隔离的内存空间。每个程序运行在其独立的虚拟地址空间中,这使得程序间的内存互不干扰。物理内存:实际的 RAM(随机存取存储器),由操作系统和硬件共同管理。虚拟

复杂SQL集合(不断收集中)

1.一道SQL语句面试题,关于group by 表内容: 2005-05-09 胜 2005-05-09 胜 2005-05-09 负 2005-05-09 负 2005-05-10 胜 2005-05-10 负 2005-05-10 负 如果要生成下列结果, 该如何写sql语句?             胜 负 2005-05-09 2 2 2005-05-10 1 2 --------

解决服务器VS Code中Jupyter突然崩溃的问题

问题 本来在服务器Anaconda的Python环境里装其他的包,装完了想在Jupyter里写代码验证一下有没有装好,一运行发现Jupyter崩溃了!?报错如下所示 Failed to start the Kernel. ImportError: /home/hujh/anaconda3/envs/mia/lib/python3.12/lib-dynload/_sqlite3.cpython-

VSC++: 括号对称比较

括号的使用规则:大括号,中括号,小括号{[()]};中括号,小括号[()];小括号();大括号、中括号、小括号、中括号、小括号、大括号{[()][()]};大括号,中括号,小括号,小括号{[(())]};大括号,中括号,小括号,小括号{[()()]};小括号不能嵌套,小括号可连续使用。 {[]}、{()}、([])、({})、[{}]、{}、[]、{[}]、[(])都属非法。 char aa[

Android 使用原始xml资源

原始XML资源一般保存在/res/xml/路径下。 XML文件中访问语法格式: @[<package_name>:]xml/file_name Java代码中访问语法格式: [<package_name>.]R.xml.<file_name> 在JAVA程序中获取实际的XML文档,可以通过Resources的如下两个方法来实现: XmlResourceParser getXml(int