(复杂值vs原始值)&&内存空间 — 准确我们的JavaScript世界观(一):
写在前面
最近在读《JavaScript启示录》,这本书不是JavaScript的详尽的参考指南,但是把对象作为了解JavaScript的透镜,受益匪浅。
那么我们先来聊一下JavaScript的原始值(值类型)以及复杂值(引用类型),以及他们在内存空间中的存储,关于他们你可能不清楚的一些事:
我们先通过一个经典的面试题类型(并不是原题,我即兴发挥)引出我们今天的主题:
我们已经看出他们的差别,在图一:我们让b = a,改变b的值,发现a并没有改变。在图二:我们让d = c,通过d.name改变对象的name属性,发现c.name也变化了。
事实上,原始值存储在栈内存中,按值来访问。复杂值(引用类型)在堆内存里面,按引用地址访问;然后我们会想到局部变量和全局变量在内存中的存储:下面是我在一个群中给一个同行的回答(前辈们莫见笑)
下面会具体介绍复杂值、原始值以及他们的一些特性与内存空间:
1、原始值是非对象
我们老生常谈的JavaScript五大基本的数据类型,null、undefined、number、string、boolean都被视为原始值,因为他们是不可细化的,本身是简单的,不能表示由其他的值组成的值。
这里需要注意的是:与使用字面量语法创建相反,在使用new关键字创建的String,Number,或Boolean值时,创建的实际上是一个复杂对象,此时已不在是原始值。
a、下面对原始值和原生JavaScript对象之间的差异进行了比较:
需要注意没有使用new关键词,从构造函数返回的字符、数字、布尔值 对比 使用字面量方法所创建的仍然不是对象。
b、我们在来对比一下使用new关键字创建的构造函数:
除了new出来的Function()对象返回的是function,其他都是object,其实在JavaScript中对函数定义非常高,因此在引用类型中,typeof能检测出函数的详细类型。
上述代码可以告诉我们:原始值不是对象,原始值的特殊之处是用于表示简单值;
2、原始值的赋值,存储,比较方式(值比较)
a、原始值在“ 面值(face value)”中的存储和操作,理解这一点非常重要,因为原始值是真实值的复制:
这里的重点是,原始值是作为不可细化的值进行存储和操作的,引用他们会转移其值:这里的意思也就是原始值(值类型)在内存中每一个值都会存储在对应的变量的中去,也就是一个真实值的”复制”。
b、原始值的比较采用引用比较
我们通过比较原始值来确定其值在字面上是否相同,
通过下面的代码来理解“值比较“的概念,并将它与复杂数字进行比较:
这里的重点是,在进行比较时,原始值会去检查表示的值是否相等,这里我们要特别和复杂值进行比较(因为复杂值不会去比较值是否相等,而是比较引用地址是否相同)
3、原始值(String,Number,Boolean)在被用做对象时就像对象
null和undefined都是非常简单的值,它们不需要构造函数,也没有new操作为自己创建JavaScript值(可以把他们当做操作符来使用即可)
原始值被当做构造函数创建的一个对象来使用时(注意不使用new),JavaScript会把其转化为一个对象,以便可以使用对象的特性(如方法),而抛弃对象的性质,并将它返回到原始值。
上述实例代码,所有的原始值(除null、undefined)都被转化为对象,以便充分利用toString()方法。一旦调用和返回改方法,对象就会被转换成对象值。这样我相信我们能很好的理解标题了
4、复杂值(复合对象、引用类型)
本质上,复杂对象其在内存中的大小是未知的,因为复杂对象可以包含任何值:
下面通过字面量的方法创建一个对象和数组
相比简单的原始值,原始值不能表示复杂值,而复杂值可以封装任意的JavaScript值
5、如何存储或复制复杂值
复杂值是通过引用来进行存储和操作的,这就回到了开始那个问题的图二,理解这一点非常重要。创建一个包含复杂对象的变量时,其值是内存中的一个引用地址。引用一个复杂对象时,使用它的名称(即变量或对象属性)通过内存中的引用地址获取对象值。当我们试图复制一个复杂值的时候,理解这就非常重要了。复杂值复制的过程、其实并不是复制对象,更多的是像复制对象的地址。
所以就像上面说过的,复制的是内存堆栈中对象的地址或者引用。
6、复杂对象比较采用引用比较
也就是说:复杂对象只有在引用相同的对象(即有相同的引用地址)时才相等:
我相信我们已经理解:指向内存中复杂对象的变量,只有在引用相同对的‘地址’的情况下才是相等的,相反,两个单独创建的对象、即使具有相同的类型并拥有完全相同的属性,他们也是不相等的。
7、复杂对象具有动态属性
通过这一点,我们可以根据需求为复杂对象有任意多个引用。
上述代码,objA、pointer1、pointer2都引用了内存中的同一对象,
【emoji罒ω罒】这三个每次调用对象的方法都会叫他‘一个人’
复杂对象支持动态对象属性,因为我们可以定义对象,然后创建引用,在更新对象、并且所有指向该对象的变量都会’获得’更新.
8、动态属性支持异变对象
复杂对象是由动态属性构成的,这一点非常重要,这使得用户自定义对象和大多数原生对象产生突变。通过增加原生对象、来改变JavaScript本身的原生预配置特性:
下面我们在原生构造函数上存储属性,并在原型对象上,向原生对象添加新方法:
所以我们明白,JavaScript的对象是动态的,这使得JavaScript对象是可变的。通过自定义我们改变了原生内部的运行机制,你会获得一个自定义版本的JavaScript来处理程序,但是使用一定要谨慎。
9、两个存储空间:栈&&堆
我们前面也提到了存储空间,在程序运行时,有两个存储空间可用,一个是栈,归属进程本身的;另一个是堆,所有进程共用的:
然后就很好理解了,因为局部变量声明在函数周期内部,在函数结束时其生命周期也就结束了,其存储空间位于栈中,当进入函数时,会根据函数内部需求,在栈申请一段内存空间,供局部变量使用。当局部变量声明周期结束后(该函数结束),在栈上释放。
由于进程栈的空间是有限的,所以1)要避免申请占用空间较大的局部变量,2)避免函数嵌套层数过多,这些都可能引起栈空间不够导致程序崩溃。
关于数据结构中栈和堆,后面还会进一步的学习总结,比如管理方式、申请大小、碎片问题、分配方式、分配效率...
写在后面
相信到这里我们对js中的原始值、复杂值、以及他们的特性、在内存中的存储有了比较深入的理解,那么让我们开始准确我们的JavaScript世界观系列,因为我从高中毕业后接触前端,对原生的热爱程度远远大于jQuery等类库。如果想实现JavaScript类库或者框架,应该打开“引擎盖”看看,了解发动机的情况。
(复杂值vs原始值)&&内存空间 — 准确我们的JavaScript世界观(一):的更多相关文章
- 复杂值vs原始值&&内存空间
写在前面 最近在读<JavaScript启示录>,这本书不是JavaScript的详尽的参考指南,但是把对象作为了解JavaScript的透镜,受益匪浅. 那么我们先来聊一下JavaScr ...
- EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态
本文目录 查看实体当前.原始和数据库值:DbEntityEntry 查看实体的某个属性值:GetValue<TValue>方法 拷贝DbPropertyValues到实体:ToObject ...
- javascript中可变值与不可变值(原始值)
字符串原始值修改不了1 var str = "abc"; 2 str[0] = "d"; 3 console.log(str[1]="f") ...
- javascript中的原始值和复杂值
× 目录 [1]特性 [2]存储方式 [3]访问方式 [4]比较方式 [5]动态属性 前面的话 javascript的数据类型可以分为两种:原始类型和引用类型.原始类型也称为基本类型或简单类型,jav ...
- Js 中的原始值和引用值
最近遇写 node.js 时到一个问题,把对象当赋值给数组成员时总是出错,比如下面的代码, var Arr = new Array(); var Obj = new Object(); for(var ...
- JS中原始值和引用值分析
JS中变量中两种类型的值:原始值,引用值 原始值是存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置. var x = 1; //1就是一个原始值,变量x中存放的就是原始 ...
- ES6 学习笔记(三)原始值与引用值
总结: 1.原始值,表示单一的数据,如10,"abc",true等. 1.1. ES的6种原始值: Undefined.Null.Boolean.Number.String.Sym ...
- JavaScript数据操作--原始值和引用值的操作本质
我的一句话总结:原始值不管是变量赋值还是函数传递都不会改变原值,引用值不管是变量赋值还是函数传递,如果新变量重新赋值,则不会影响原引用值,如新变量是直接操作,就会影响原引用值. 首先明确,值和类型是两 ...
- JavaScript中对象转换为原始值的规则
JavaScript中对象转换为原始值遵循哪些原则? P52 对象到布尔值对象到布尔值的转换非常简单:所有的对象(包括数字和函数)都转换为true.对于包装对象亦是如此:new Boolean(fal ...
随机推荐
- 关于Django的理解
Django的理解 Django的核心是中间件, 所有的请求和响应都会经过中间件 中间件是一个钩子框架, 它们可以介入请求的响应处理过程, 它用于在全局修改Django的输入和输出 Django有以下 ...
- jquery.imagezoom.js制作鼠标悬停图片放大镜特效、参数和最简教程
一.插件介绍 今天在用到放大镜效果的时候,突然发现网站里没有放大镜的插件.于是总结了一下,放到这里.为自己,也为他人提供方便.jquery.imagezoom.js这款插件用途很简单,就是鼠标移过去, ...
- C# Process.Start()
本文转自:http://webcache.googleusercontent.com/search?q=cache:v4Sh6GlfJPYJ:blog.csdn.net/czw2010/article ...
- Solr(五)Solr实现简单的类似百度搜索高亮功能-2代码
Solr高亮 一 在配置文件中,配置支持Ik分词器的Field 修改文件: cd /usr/local/tomcat/apache-tomcat-8.5.13/solr_home/Test/conf/ ...
- akoj-1369 贪吃蛇
贪吃蛇 Time Limit:1000MS Memory Limit:65536K Total Submit:9 Accepted:2 Description 有童年的孩子都玩过这个经典游戏,不过这里 ...
- Java中parse()和valueOf(),toString()的区别
1.parse()是SimpleDateFomat里面的方法,你说的应该是parseInt()或parsefloat()这种方法吧, 顾名思义 比如说parseInt()就是把String类型转化为i ...
- 纯JavaScript实现异步Ajax的基本原理
Ajax实际就是XMLHttpRequest对象和DOM.(X)HTML和CSS的简称,用于概括异步加载页面内容的技术. Ajax实例 HTML代码如下,包含一个h5标题和一个按钮: JS代码如下 ...
- 你不可错过的二维码生成与解析-java后台与前端js都有
1.二维码分类 二维条码也有许多不同的码制,就码制的编码原理而言,通常分为三种类型. 线性堆叠式二维码 编码原理: 建立在一维条码基础之上,按需要堆积成两行或多行. 图示: 矩阵式二维码 最常用编 ...
- 中点Bresenham画圆
这里不仔细讲原理,只是把我写的算法发出来,跟大家分享下,如果有错误的话,还请大家告诉我,如果写的不好,也请指出来,一起讨论进步. 算法步骤: (1) 输入圆的半径R. (2) 计算初始值d = 1 - ...
- Entity Framework - 基于外键关联的单向一对一关系
代码的世界,原以为世界关系很简单,确道是关系无处不在.NET世界里ORM框架中EntityFramework作为其中翘楚,大大解放了搬砖工作的重复工作,着实提高了不少生产力,而也碰到过不少问题!比如关 ...