js 中的栈和堆
js中的栈与堆的讲解/基本数据类型与引用类型的讲解
前言:1. 学习前端,入门简单,想学好确实是一件很困难的事情,东西多而且杂,版本快速迭代,产品框架层出不穷。
2. 前端学习成本确实很高,需要不断的学习和夯实基础,当初学的时候,一讲到堆栈就一脸懵逼,搞了很久才豁然开朗,把这个放在这里,
是希望更多的人能先了解一些基础的东西,学习起新知识能够更好的掌握。
1、栈(stack)和堆(heap)
stack为自动分配的内存空间,它由系统自动释放;而heap则是动态分配的内存,大小不定也不会自动释放。
2、基本类型和引用类型
基本类型:存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。
5种基本数据类型有Undefined、Null、Boolean、Number 和 String,它们是直接按值存放的,所以可以直接访问。
引用类型:存放在堆内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置。每个空间大小不一样,要根据情况开进行特定的分配。
当我们需要访问引用类型(如对象,数组,函数等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。
为什么会有栈内存和堆内存之分?
通常与垃圾回收机制有关。为了使程序运行时占用的内存最小。
当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;
当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。
3、传值与传址
前面之所以要说明什么是内存中的堆、栈以及变量类型,实际上是为下文服务的,就是为了更好的理解什么是“浅拷贝”和“深拷贝”。
基本类型与引用类型最大的区别实际就是传值与传址的区别。测试用例:
1 var a = [1,2,3,4,5]; 2 var b = a;//传址 ,对象中传给变量的数据是引用类型的,会存储在堆中; 3 var c = a[0];//传值,把对象中的属性/数组中的数组项赋值给变量,这时变量C是基本数据类型,存储在栈内存中;改变栈中的数据不会影响堆中的数据 4 alert(b);//1,2,3,4,5 5 alert(c);//1 6 //改变数值 7 b[4] = 6; 8 c = 7; 9 alert(a[4]);//610 alert(a[0]);//1
从上面我们可以得知,当我改变b中的数据时,a中数据也发生了变化;但是当我改变c的数据值时,a却没有发生改变。
这就是传值与传址的区别。因为a是数组,属于引用类型,所以它赋予给b的时候传的是栈中的地址(相当于新建了一个不同名“指针”),而不是堆内存中的对象。而c仅仅是从a堆内存中获取的一个数据值,并保存在栈中。所以b修改的时候,会根据地址回到a堆中修改,c则直接在栈中修改,并且不能指向a堆内存中。
3、浅拷贝
前面已经提到,在定义一个对象或数组时,变量存放的往往只是一个地址。当我们使用对象拷贝时,如果属性是对象或数组时,这时候我们传递的也只是一个地址。因此子对象在访问该属性时,会根据地址回溯到父对象指向的堆内存中,即父子对象发生了关联,两者的属性值会指向同一内存空间。
1 var a = { 2 key1:"11111" 3 } 4 function Copy(p) { 5 var c = {}; 6 for (var i in p) { 7 c[i] = p[i]; 8 } 9 return c;10 }11 a.key2 = ['小辉','小辉'];12 var b = Copy(a);13 b.key3 = '33333';14 alert(b.key1); //111111115 alert(b.key3); //3333316 alert(a.key3); //undefined
a对象中key1属性是字符串,key2属性是数组。a拷贝到b,12属性均顺利拷贝。给b对象新增一个字符串类型的属性key3时,b能正常修改,而a中无定义。说明子对象的key3(基本类型)并没有关联到父对象中,所以undefined。
1 b.key2.push("大辉");2 alert(b.key2); //小辉,小辉,大辉3 alert(a.key2); //小辉,小辉,大辉
但是,若修改的属性变为对象或数组时,那么父子对象之间就会发生关联。从以上弹出结果可知,我对b对象进行修改,a、b的key2属性值(数组)均发生了改变。其在内存的状态,可以用下图来表示。
原因是key1的值属于基本类型,所以拷贝的时候传递的就是该数据段;但是key2的值是堆内存中的对象,所以key2在拷贝的时候传递的是指向key2对象的地址,无论复制多少个key2,其值始终是指向父对象的key2对象的内存空间。
4、深拷贝
或许以上并不是我们在实际编码中想要的结果,我们不希望父子对象之间产生关联,那么这时候可以用到深拷贝。既然属性值类型是数组和或象时只会传址,那么我们就用递归来解决这个问题,把父对象中所有属于对象的属性类型都遍历赋给子对象即可。测试代码如下:
1 function Copy(p, c) { 2 var c = c || {}; 3 for (var i in p) { 4 if (typeof p[i] === 'object') { 5 c[i] = (p[i].constructor === Array) ? [] : {}; 6 Copy(p[i], c[i]); 7 } else { 8 c[i] = p[i]; 9 }10 }11 return c;12 } 13 a.key2 = ['小辉','小辉'];14 var b={};15 b = Copy(a,b); 16 b.key2.push("大辉");17 alert(b.key2); //小辉,小辉,大辉18 alert(a.key2); //小辉,小辉
由上可知,修改b的key2数组时,没有使a父对象中的key2数组新增一个值,即子对象没有影响到父对象a中的key2。其存储模式大致如下:
js 中的栈和堆的更多相关文章
- js中的栈、堆、队列、内存空间
栈(stack) .堆(heap). 队列(queue)是js的三种数据结构. 栈(stack) 栈的特点是"LIFO,即后进先出(Last in, first out)".数据存 ...
- JS中的栈和堆
一.栈和堆 栈(stack):栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间. 基本类型:String,Number,Boolean,Null,Undefined 堆 ...
- js中的栈,堆。
一.栈和堆 栈(stack):栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间. 基本类型:String,Number,Boolean,Null,Undefined 堆 ...
- js中的栈与堆的讲解/基本数据类型与引用类型的讲解
1.栈(stack)和堆(heap) stack为自动分配的内存空间,它由系统自动释放:而heap则是动态分配的内存,大小不定也不会自动释放. 2.基本类型和引用类型 基本类型:存放在栈内存中的简单数 ...
- 关于VS中更改栈和堆空间的大小
编号:1008时间:2016年4月12日17:01:38功能:关于VS中更改栈和堆空间的大小 URL:http://blog.csdn.net/icerock2000/article/details/ ...
- 浅谈Java中的栈和堆
人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数 ...
- Java中的栈,堆,方法区和常量池
要说Java中的栈,堆,方法区和常量池就要提到HotSpot,HotSpot是Sun JDK 和 Open JDK中所带的虚拟机. (Sun JDK 和 Open JDK除了注释不同,代码实现基本上是 ...
- JAVA中的栈和堆
JAVA在程序运行时,在内存中划分5片空间进行数据的存储.分别是:1:寄存器.2:本地方法区.3:方法区.4:栈.5:堆. 基本,栈stack和堆heap这两个概念很重要,不了解清楚,后面就不用学了. ...
- JAVA中的栈和堆【转】
原文链接 https://www.cnblogs.com/ibelieve618/p/6380328.html JAVA在程序运行时,在内存中划分5片空间进行数据的存储.分别是:1:寄存器.2:本地方 ...
随机推荐
- Vue自定义插件方法大全
新年第一天首先祝大家新年快乐,心想事成! 1.利用根实例构造函数的原型 //在构造函数的原型链上添加自定义属性 Vue.prototype.test = 'pomelo' //在其他组件中调用 con ...
- poj-1218 THE DRUNK JAILER 喝醉的狱卒
自己去看看原题; 题目大意: 就是一个狱卒喝醉了,他第一趟吧所有的监狱都带开,第二趟把能把二整除的监狱关闭,第三趟操作能把三整除的监狱; 求最后能逃跑的罪犯数 输入第一个数是代表 测试数据组数 每个数 ...
- 读headFirst设计模式 - 观察者模式
上次学习了策略模式,这次来学习观察者模式.这次先把书上的例子学习一下,然后再自己写一个例子,看是否能做到举一反三(或者说触类旁通),不过要想真正的掌握还要多多思考和练习. 学习书上的例子 现在我们有一 ...
- 【Bootstrap】 bootstrap-select2下拉菜单插件
这次开发了个小TRS系统,虽然是很小,但是作为初心者,第一次用到了很多看起来洋气使用起来有相对简单的各种前端(主要是和bootstrap配合使用)组件.包括bootstrap-select2,boot ...
- 源码实现 --> itoa函数实现
itoa函数实现 itoa()函数的功能是将一个整数转换为一个字符串 例如12345,转换之后的字符串为"12345",-123转换之后为"-123",欢迎大家 ...
- 源码实现 --> atoi函数实现
atoi函数实现 atoi()函数的功能是将一个字符串转换为一个整型数值. 例如“12345”,转换之后的数值为12345,“-0123”转换之后为-123. #include <stdio.h ...
- 浅谈new/delete和malloc/free的用法与区别
每个程序在执行时都会占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为自由存储区或堆. 一.new和delete用法 如下几行代码: int *pi=new int; int *pi=ne ...
- 关于js中promise的面试题。
核心点promise在生命周期内有三种状态,分别是pending,fulfilled或rejected,状体改变只能是 pending-fulfilled,或者pending-rejected.而且状 ...
- HA集群heartbeat配置--Nginx
HA即(high available)高可用,又被叫做双机热备,用于关键性业务.简单理解就是,两台机器A和B,正常是A提供服务,B待命限制,当A宕机或服务宕掉,会切换至B机器继续提供服务.常用实现高可 ...
- grep -vFf 比较2个文件差异
grep -vFf 1.txt 2.txt 打印出2.txt中与1.txt有差异的数据. #cat .txt 192.168.0.1 192.168.0.2 192.168.0.3 #cat .t ...