先思考一下:
//以下的结果是什么?
{}=={}
[]==[]
''==''
堆(heap)与栈(stack)
在JavaScript中简单数据类型是放在栈中的,复杂数据类型是放在堆中的。
基本类型:这些类型在内存中分别占有固定大小的空间,他们的值保存在栈空间,我们通过按值来访问的
引用类型:引用类型,值大小不固定,栈内存中存放地址指向堆内存中的对象。是按引用访问的。
区别
栈(stack)会自动分配内存空间,会自动释放。堆(heap)动态分配的内存,大小不定也不会自动释放。
堆:队列优先,先进先出;由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。
栈:先进后出;动态分配的空间 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
传值和传址
本类型与引用类型最大的区别实际就是传值与传址的区别。
- 从一个向另一个变量复制 引用类型 的值,复制的其实是指针(也就是栈中地址,这个地址指向堆中的对象),因此两个变量最终指向堆中的同一个对象。即复制的是栈中的地址而不是堆中的对象。
- 从一个变量复向另一个变量复制基本类型的值,会创建这个值的副本。也就是会在栈中重新开辟一个新的内存空间,并给它赋值。
举例:
<script>
var a=4;
var b=a;
a=10;
console.log(a,b); //结果:10,4
</script>
基本类型是放到栈中的,首先是在栈中为,开辟一个内存空间存放4并赋值给a,然后再为开辟一个内存空间也存放4并赋值给b,然后修改a的值为10,因为a,b的内存地址不一样,所以互不影响。
图解:(图片没处理,可以先下载然后放大看)
var obj = {
a:1,
b:2
}
var obj1 = obj;
console.log(obj1,obj);
obj.a = 20;
console.log(obj);//修改了obj的值,obj1的值也改变了
obj1.b = 30;
console.log(obj);
复杂类型是放到堆中的。
看图解,更加清晰易懂!!(下载先放大看吧嘻嘻!)
关于复杂数据类型赋值的方式图解
也凑合下载放大看吧!
堆栈溢出
上边说道栈的数据会自动清除,而堆中的数据不会自动清除,需要手动清除。
每次存储数据,就会造成堆中的东西一直在增加,也就是当存储的数据达到某一限制时,就会造成堆栈溢出。
内存泄漏
当不断的向堆中存储数据,而不进行清理,这就是内存泄漏。(内存泄漏的结果就是堆栈溢出)
垃圾回收机制
为了不让内存泄漏,清理的方式就叫【垃圾回收机制】,(栈中不用的就自动清理,而堆不能)
一般分为两种:一种是自动清理,一种是手动清理(gc机制)。js中只有自动清理。清理的对象也可以叫做 ‘孤儿对象’ 。(堆中的数据的地址在栈中没有任何引用,这个堆中的数据对象就叫孤儿对象)
垃圾回收机制:就是将引用堆中地址的对象设置为null,并且将所有引用该地址的对象都设置为null,但是不会即时清除,因为垃圾回收车会根据内存的情况在适当的时候清除堆中的’孤儿对象’(也就是这个对象没有任何引用)
例如: 对上边的例子进行垃圾回收
设置 obj=null; 在栈中把obj的值设置为null,此时obj就没有引用堆中的数据对象,但是不会把堆中的数据对象清除掉,因为obj1还在引用它,所以堆中的数据对象,还不是"孤儿",只有把obj1也设置为null,垃圾回收车才会在适当的时机把堆中的数据孤儿清理掉。
总结:如果想要清除复杂数据类型,也就是堆中的数据,必须将所有引用堆中地址的对象设置为null。