小米技术社区
小米技术社区管理员 关于小米

27岁,山西运城人,职业电商经理人,前端开发工作者,从事过网站建设、网络推广、SEO、SEM、信息流推广、二类电商、网络运维、软件开发,等相关电商工作,经验较为丰富,小米技术社区致力于为广大从事Web前端开发的人员提供一些力所能及的引导和帮助 ...[更多]

E-mail:mzze@163.com

Q Q:32362389

W X:xiaomi168527

小米技术社区大牛王飞 关于王飞

27岁,山西运城人,职业电商经理人,网络工程师兼运维,从事过运营商网络建设,企业网络建设、优化。数据中心网络维护等通过,经验丰富,座右铭:当自己休息的时候,别忘了别人还在奔跑。 ...[更多]

E-mail:wf_live@126.com

Q Q:3940019

微博:王小贱ss

小米技术社区设计小艳 关于小艳

大于花一样的年龄,河南郑州是我家,2010年在北京接触团购网,2011年进入天猫淘宝一待就是四年,如今已经将设计走向国际化(ps:误打误撞开始进入阿里巴巴国际站的设计,嘿嘿)五年电商设计,丰富经验,从事过天猫淘宝阿里各项设计,店铺运营,产品拍摄;我将我的经历与您分享是我的快乐!座右铭:越努力越幸运! ...[更多]

E-mail:97157726@qq.com

Q Q:97157726

标签云
精品推荐
  • 什么是闭包?js闭包的2个最大用途以及注意事项

    什么是闭包?js闭包的2个最大用途以及注意事项

    各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。简单的说,闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因……
    199人已经看过了
您的位置:首页 > 前端开发 > Javascript > 原生JS

js数据在内存中的存储[值传递]和[引用传递]以及栈区和堆区的区别

分类: 原生JS26个赞

内存地址分区:

image.png

js数据传值方式分为: 


值传递 :基本数据类型,直接将变量放在栈区的值,复制一份,传给另外一个变量。

引用传递:对象类型,将变量放在堆区的值的地址,传给另外一个变量。


要了解以上概念,我们先了解js内存数据存储的机制.

内存里面划分为不同的区,存不同的东西(和电脑盘一样),内存存储主要划分为5个区域:

1.栈区:

存放简单类型的数据,操作比较快,但程序员是无法控制的。

增值类型:向下增长  先来的数据放在最下面,一开始的序号大

空间大小:很小 只有2M左右

由编译器自动分配释放 ,存放函数的参数值,局部变量的值等,内存的分配是连续的,类似于平时我们所说的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,即,所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器会自动接着当前栈区的结尾来分配内存.

在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。

基本类型:非对象的string number boolean undefined null 数据直接存储在栈区

2.堆区

存放复杂数据,操作比较慢 

增值类型:向上增长  一开始的序号小

 一般由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收.类似于链表,在内存中的分布不是连续的,它们是不同区域的内存块通过指针链接起来的.一旦某一节点从链中断开,我们要人为的把所断开的节点从内存中释放.

堆是向高地址扩展的数据结构,是不连续的内存区域。

空间大小: 很大,随便存,数据变量多没问题

引用类型对象(array  object  function)  堆区存数据,  栈区存数据在堆区的地址


3.全局区(静态区)

js里面基本用不上,因为变量基本不存在静态变量

全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 程序结束后由系统释放


4.常量区

CS6之前没有常量,从CS6才开始有

常量字符串就是放在这里的。 程序结束后由系统释放

5.代码区

放置函数体,比如定义一个函数,大括号里面的函数体


栈区和堆区的区别

速度区别

栈由系统自动分配,速度较快。但程序员是无法控制的。

堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.

另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,它不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。


堆和栈中的存储内容区别

栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。


当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。


堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。


堆和栈中存取效率的比较

char s1[] = "aaaaaaaaaaaaaaa";

char *s2 = "bbbbbbbbbbbbbbbbb";


aaaaaaaaaaa是在运行时刻赋值的;

而bbbbbbbbbbb是在编译时就确定的;

但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。


堆和栈的区别可以用如下的比喻来看出:

使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。


使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。


内存存储操作案例理解

栈区案例:

基本类型:非对象 string  number  boolean  undefined null  数据直接存储在栈区

let a =1 ; 
let b =1;
变量栈区堆区
a1
b1
var a = 1; 
var b = a; 
b = 2;
变量栈区堆区
a1
b2

堆区案例:

引用类型:对象(array  object  function)  堆区存数据,  栈区存数据在堆区的地址

var obj = {"age":40, "sex":"男"};
变量栈区堆区
obj00000001(堆区地址){"age":40, "sex":"男"}
b2
var obj = {"age":40, "sex":"男"}; var obj2 = obj;
变量栈区堆区
obj00000001(堆区地址){"age":40, "sex":"男"}
obj200000001这里还是指向上面那个堆区
var obj = {"age":40, "sex":"男"}; 
var obj2 = obj; 
obj2.age = 30;


变量栈区堆区
obj00000001(堆区地址){"age":30, "sex":"男"} //修改了这里的40为30
obj200000001


栈区和堆区区别导致的使用过程中存在的问题

	//普通值(基本类型)
	var a = 1;
	var b = a;
	console.log(a, b);//结果为1,2

	b = 2;
	console.log(a, b);  //结果为1,2

	//特殊的---对象(复杂类型)
	var obj = {"age":40, "sex":"男"};
	var obj2 = obj;
	console.log(obj, obj2); //结果为2个{"age":40, "sex":"男"};

	obj2 = {'age':30};
	console.log(obj, obj2);  //结果为2个{"age":30, "sex":"男"}; 疑问?为什么只修改了obj2,1也改了
	

	//说明  obj 和 obj2两个变量,存储的是一个对象,是共用的
	
	//函数参数 如果是对象
	function fn(m){
		m.age = 30;
		console.log(m);
	}

	var obj = {"age":40, "sex":"男"};
	fn(obj);
	console.log(obj); //obj.age被改为 30


小米技术社区