js 自动分配金额_JS内存图以及原型与原型链

内存以及内存图

在JS中,每一个数据都需要一个内存空间。内存空间又被分为两种,栈内存(stock)与堆内存(heap)JS内存空间分为栈(stack)、堆(heap)、池(一般也会归类为栈中)。 其中栈存放变量,堆存放复杂对象,池存放常量。

JS中的基础数据类型,这些值都有固定的大小,往往都保存在栈内存中(闭包除外),由系统自动分配存储空间。我们可以直接操作保存在栈内存空间的值,因此基础数据类型都是按值访问 数据在栈内存中的存储与使用方式类似于数据结构中的堆栈数据结构,遵循后进先出的原则。 基础数据类型: Number String Null Undefined Boolean ~ ~ 要简单理解栈内存空间的存储方式,我们可以通过类比乒乓球盒子来分析。

72c2872c23f3a3c9bf413f25180ba65f.png

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

JS的复杂数据类型,比如数组Array,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JS不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联。 堆存取数据的方式,则与书架与书非常相似。 书虽然也有序的存放在书架上,但是我们只要知道书的名字,我们就可以很方便的取出我们想要的书,而不用像从乒乓球盒子里取乒乓一样,非得将上面的所有乒乓球拿出来才能取到中间的某一个乒乓球。好比在JSON格式的数据中,我们存储的key-value是可以无序的,因为顺序的不同并不影响我们的使用,我们只需要关心书的名字。

JS里所有的数字都是以64位浮点数储存的,16位存储一个字符,所以在栈内存内都是64位01
我们来看看代码:

var a = 20
var b = a
b=30

b=a,那就把a存的东西复制然后覆盖到b储存的地方。

1665f1199ccf3cd53420ae1b3161acae.png

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

再复杂一点,我们存储复杂类型呢?也就是heap内存里是怎样呢?

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

就像上述代码,当需要存储字符的时候,一行64位浮点数,只能存储4个字符,非常浪费且再添加属性的时候就需要整体移动下位的代码,很麻烦,所以我们就在栈内存里存储一个地址,地址随意,但是这个地址指向heap内存里相应地址的位置,而我们需要储存的内容就写在这里。
我们通过var n = m执行一次复制引用类型的操作。引用类型的复制同样也会为新的变量自动分配一个新的值保存在栈内存中,但不同的是,这个新的值,仅仅只是引用类型的一个地址指针。当地址指针相同时,尽管他们相互独立,但是在堆内存中访问到的具体对象实际上是同一个。

如图所示

4cb1f1605bc1a24032d5a376c1c8f385.png

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

以上就是js中的内存和内存图,遇到不明白的地方,多画图就能弄明白了。

内存释放

因为JavaScript具有自动垃圾收集机制,JavaScript的内存生命周期是

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

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

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

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

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

var a = {name:'xx'}
var b = {name:'yy'}
// 代码区                    // stack                  //Heapa                        ADDR 888                   xxb                        ADDR 666                   yy
// 当b =a
//代码区                     // stack                  //Heapa                        ADDR 888                   xxb                        ADDR 888                   (yy未被引用,被释放)

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

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

深拷贝与浅拷贝


var a = 1 var b = a b = 2 a // 1
像这样,b改变不会影响a,这就是深拷贝
对于所有的基本类型,赋值都是深拷贝,所以我们来研究对象。

var a={name:'}
var b=a
b.name='b'
a.name//'b'

如上述,b.name = 'b' ,改变name的值,引用a,得到的也是改变后的。
像这样,b的改变会导致a的改变,就是浅拷贝。

全局对象 window

ECMAScript 规定全局对象叫做 global,但是浏览器把 window 作为全局对象(浏览器先存在的)

window 就是一个哈希表,有很多属性。

window 的属性就是全局变量。

这些全局变量分为两种:

  1. 一种是 ECMAScript 规定的
  • global.parseInt
  • global.parseFloat
  • global.Number
  • global.String
  • global.Boolean
  • global.Object
  1. 一种是浏览器自己加的属性
  • window.alert
  • window.prompt
  • window.comfirm
  • window.console.log
  • window.console.dir
  • window.document
  • window.document.createElement
  • window.document.getElementById

所有 API 都可以在 MDN 里找到详细的资料。

今天我们学习第一种全局变量。

全局函数

  1. Number
    var n = new Number(1) 创建一个 Number 对象
    1 与 new Number(1) 的区别是什么?
  2. String
    var s = new String('hello') 创建一个 String 对象
    'hello' 与 new String('hello') 的区别是什么?
  3. Boolean
    var b = new Boolean(true) 创建一个 Boolean 对象
    true 与 new Boolean(true) 的区别是什么?
  4. Object
    var o1 = {}
    var o2 = new Object()
    o1 和 o2 没区别


上面的区别在于,只要我们引用上述字符串的属性,JavaScript就会将字符串值通过调用new String(s)的方式转换成对象,之后字符串继承了对象的方法,处理属性的引用。属性引用结束,这个新创建的对象就被销毁。
我们可以这样来想,我们既想用简单类型,又想获得对象的方法,然后Branden Eich就想了个办法,我们可以建立临时对象,获取属性后返回给调用,然后销毁就可以。

var n = ‘a'
n.toString()
// 代码区             // stack               // heapn                     'a'temp                  ADDR 888             888: 'a'toSting()valueOf()


temp就是临时对象,当调用toString返回后,temp马上被销毁了。
其他的数据类型也是一样,
调取属性的背后都是这样一套操作。

原型与原型链

从上面我们可以看到,利用new创建并初始化一个新对象,运算符new后面跟着一个函数调用,叫做构造函数。
var s = new String('hello')
如上述代码,s就是被创建的实例对象,new运算符后跟着的String(注意这里开头必须大写来和string区分)就是构造函数。
我们可以看到从实例对象中调用的属性,但是他们都具有的属性比如toString以及valueOf等,如果每个实例对象都在heap存储处生成这些都有的属性岂不是很费内存?所以我们可以共有属性归拢起来,然后通过 __proto__ 来指向共有属性。公用的属性藏在哪

JavaScript中的对象,都有一个内置属性[[Prototype]],指向这个对象的原型对象。当查找一个属性或方法时,如果在当前对象中找不到定义,会继续在当前对象的原型对象中查找;该原型对象也有一个自己的原型对象(__proto__) ,层层向上直到一个对象的原型对象为null。根据定义,null没有原型,并作为这个原型链中的最后一个环节。

可以看出,这个查找过程是一个链式的查找,每个对象都有一个到它自身原型对象的链接,这些链接组件的整个链条就是原型链。拥有相同原型的多个对象,他们的共同特征正是通过这种查找模式体现出来的。
在上面的查找过程,我们提到了最顶层的原型对象,这个对象就是Object.prototype,这个对象中保存了最常用的方法,如toStringvalueOfhasOwnProperty等,因此我们才能在任何对象中使用这些方法。

如下图:

c57493e53ffbd065871dd8692db5a7bd.png

重要公式

var 对象 = new 函数()
对象.__proto__ === 对象的构造函数.prototype// 推论
var number = new Number()
number.__proto__ = Number.prototype
Number.__proto__ = Function.prototype // 因为 Number 是 Function 的实例var object = new Object()
object.__proto__ = Object.prototype
Object.__proto__ = Function.prototype // 因为 Object 是 Function 的实例var function = new Function()
function.__proto__ = Function.prototype
Function.__proto__ == Function.prototye // 因为 Function 是 Function 的实例!

(以上部分资料来自网络,仅供自己学习参考,侵删)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/488462.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全球首个AI宇宙模拟器不仅有6亿光年宽度,还“自行”跑出了暗物质

来源:大数据文摘《创世纪》里,神用7天创造了这个世界。而现在,你可能也有机会体验这个过程,创造一个属于自己的宇宙。Space Engine 0.990版本在Steam平台发售不到一天,近300测评全部为最高评价。之后,还得到…

一个HelloWorld网站

一个HelloWorld网站 点击直达 介绍 很多技术在里面都有很多的HelloWorld 当初是我在windows下使用redis在官方文档没有找到入门的资料发现的 个人理解 作为HelloWorld是不错的,当然还有一些东西值得看,参考用过直接上某个技术的官方文档。 转载于:https://www.cnblogs.com/bean…

js 延迟几秒执行_深入研究 Node.js 的回调队列

// 每日前端夜话 第365篇// 正文共:3000 字// 预计阅读时间:10 分钟队列是 Node.js 中用于有效处理异步操作的一项重要技术。在本文中,我们将深入研究 Node.js 中的队列:它们是什么,它们如何工作(通过事件循环)以及它们…

java官方 jax rs_jboss7 Java API for RESTful Web Services (JAX-RS) 官方文档

原文:https://docs.jboss.org/author/display/AS7/JavaAPIforRESTfulWebServices(JAX-RS)ContentTutorial OverviewThis chapter describes the Java API for RESTful web services (JAX-RS, defined in JSR331). RESTEasy is an portable implementation of this s…

数据结构-王道2017-第5章 图

1.图的基本概念 1)图的定义 图G由顶点集V和边集E组成,记为G(V,E),其中V(G)表示图G中定点的有限非空集;E(G)表示图G中顶点之间的关系(边)集合。V{v1,v2,..,vn},用|V|表示图G中顶点的个数,也称为图G的阶&…

python两个参数or循环_python学习笔记(四)、条件、循环及其他语句

1 再谈print和import1.1 打印多个参数print 能够同时打印多个表达式,并且能自定义分隔符。如下:print(a,b,c)  ——> a b cprint(a,b,c,sep"_")  ——> a_b_c1.2 import导入模块时,能够给导入的模块取一个别名(相对于生活…

研究揭示大脑在工作记忆中存储信息的神经机制

来源:中国科学院脑科学与智能技术卓越创新中心(神经科学研究所)3月5日,《神经元》期刊在线发表了题为《无颗粒岛叶皮层瞬时性神经元活动调控学习新任务时的工作记忆存储》的研究论文。该研究由中国科学院脑科学与智能技术卓越创新…

[Jmeter] 基本使用的总结

转载于:https://www.cnblogs.com/mytianying/p/6793461.html

java 仿qq登录界面7.1_安卓开发学习笔记(七):仿写腾讯QQ登录注册界面

这段代码的关键主要是在我们的相对布局以及线性布局上面,我们首先在总体布局里设置为线性布局,然后再在里面设置为相对布局,这是一个十分常见的XML布局模式。废话不多说,直接上代码:一.activity.xml>android:layout…

python numpy.array_python的numpy.array

为什么要用numpyPython中提供了list容器,可以当作数组使用。但列表中的元素可以是任何对象,因此列表中保存的是对象的指针,这样一来,为了保存一个简单的列表[1,2,3]。就需要三个指针和三个整数对象。对于数值运算来说,…

【前沿科技】云计算军事运用有啥特点

来源: 军语开源情报研究所云计算技术被视为继大型计算机、个人计算机、互联网之后的第四次信息技术产业革命。云计算是一种围绕分布式共享计算资源的创新应用模式,资源提供者可以方便而快速地提供计算资源,而无处不在的资源需求者可以便利地使…

tools URL 收集

每次恢复快照都会把CHrome的标签弄没,所以将收藏的好资源放在这里以免又丢了。 IP 段查询下载,做黑白名单用的到 http://ipblock.chacuo.net/ 转载于:https://www.cnblogs.com/M4ster/p/tools_url.html

python 通过ip获取城市_python 根据ip获取地理位置

!/usr/bin/pythoncodingutf-8import dpktimport socketimport pygeoipimport optparsegi pygeoip.GeoIP(GeoLiteCity.dat)查询数据库相关的城市信息并输出def printRecord(tgt):rec gi.record_by_name(tgt)city rec[city]# 原来的代码为 region rec[region_name]&#xff0…

js原型和原型链_JS 构造函数与原型链

JavaScript 对象体系是基于构造函数和原型链的。继承不通过类,而是通过原型对象实现,原型对象的所有属性和方法,都能被实例对象共享。构造函数(constructor)在 JS 中想要生成可重用、可继承的对象就要使用构造函数&…

全球制造业的未来

来源:航空简报2020年3月4日,Brahima Coulibaly和Karim Foda在美国布鲁金斯学会官网刊文,分析了全球制造业的未来,提出了几个鲜明的观点:1.“比较优势”将发生转移,中等收入国家尤其是许多亚洲新兴经济体&am…

关于解决织梦文档栏目删除后ID 从1开始的方法

在织梦当删除文档栏目后,再重新建立文档时,它的id就会按照刚才建立的文档的id的数值再增加一个, 比如,开始建立的文档id是1,当删除后,要重新再建立一个文档时,文档的后面的id已经不是从1开始&am…

mybatis 批量修改_解放双手,不写SQL!一个开源 MyBatis 神器!!

什么是通用 Mapper?它是一个可以方便的使用 Mybatis 进行单表的增删改查优秀开源产品。它使用拦截器来实现具体的执行 Sql,完全使用原生的 Mybatis 进行操作。在 Github 上标星 9.6K!为什么要用 Mapper?它提供了所有单表的基本增删…

论文速读:AI能从人类的愚蠢中学到什么?

来源:混沌巡洋舰本文来自对下面论文的编译和解读:导读:随着机器在某些认知问题上超越人类,人机协作将会带来越来越显著的影响。造成人类偏见的三个主要原因(小而不完整的数据集,从自己的决策结果中学习&…

struts2的核心和工作原理

在学习struts2之前,首先我们要明确使用struts2的目的是什么?它能给我们带来什么样的优点? 设计目标 Struts设计的第一目标就是使MVC模式应用于web程序设计。在这儿MVC模式的优点就不在提了。技术优势 Struts2有双方面的技术优势,一…

python函数递归法求一个数各位数之和_python – 设计一个使用digit_sum计算数字总和的递归函数...

要获得(正整数)数字的最后一位数,您可以计算模数&#xff1a;last_digit n % 10该数字的其余部分(不包括最后一个地方)是&#xff1a;rest (n - last_digit) / 10理论上这应该足以分割数字并添加数字&#xff1a;def sum_digits(n):if n < 10:return nelse:last_digit n …