堆栈内存的区别
堆栈内存的区别(看图)
let a = 12;
let b = a;
let c = {name: 'xiaoHua'};
b = 13;
console.log(a, c)
——————————————————————————————————————————————
let a = {n:1};
let b = a;
a.x = a = { // 像这种连续等于要从左往右依次赋值
n:2
};
console.log(a.x, b);
堆内存和栈内存
打开一个页面,浏览器会形成两个虚拟的内存:堆内存、栈内存
栈内存存储了啥:变量、基本数据类型值、地址
堆内存存储了啥:存储了引用数据类型的值
PS:全局作用域、私有作用域都是栈内存,为代码执行提供必要的环境,理论上来说,存储的东西越少,运行的越快
堆栈内存销毁
-
堆内存回收
堆内存回收:GC垃圾回收机制;在浏览器内置了一个gC程序,这个程序会每隔一段时间执行一次;
- 谷歌浏览器-标记法:浏览器每隔一段时间要对所有的空间地址类型进行检测,检查该地址是否被占用;如果没有占用,那么久立即回收掉
- IE和火狐-计数法:浏览器采用计数的规则,如果空间地址被占用一次,那这个空间地址就默认+1,每空闲一次,空间地址就默认-1,如果浏览器发现有为0的空间地址,就把其回收
-
堆内存销毁
var obj = {};
obj = null;
// 谷歌浏览器:
- 栈内存回收==>作用域销毁
- 栈内存的销毁:立即销毁、不销毁 、不立即销毁
- 作用域就是栈内存:全局作用域、私有作用域
- 全局作用域的销毁: 一般情况情况不销毁,除非把当前页面关闭,整个作用域就销毁了
- 私有作用域的销毁:立即销毁、不销毁 、不立即销毁
- 不销毁:
- (1)函数(包括自执行函数)要return一个引用数据类型值,(2),return要被外界接收
- 如果当前作用域有个空间地址,被函数体外的东西占用着,那么这个栈内存就不能销毁;
- 对象键值对的属性名对应的是个自执行函数并且返回值的是个函数,自执行函数作用域不销毁。
- 不立即销毁:fn()()return一个小函数,马上让小函数执行,这时候外界的作用域不能立即销毁,他要等待小函数执行完成之后再销毁
- 立即销毁:不能同时满足上边的两个条件,作用域就销毁了
- 作用域销毁的例子
- 不销毁:
- 作用域就是栈内存:全局作用域、私有作用域
/* var i = 5;
function fn(i) { // 1 2 3
return function (n) { // 2 7
console.log(n + (++i)); // 4 10
}
}
var f = fn(1);
f(2);
fn(3)(4);
fn(5)(6);
f(7);
console.log(i); // 5
// function fn(){
// var name = 'jinYu',
// age = 18;
// }
// fn();
// fn();
// (1)函数要return一个引用数据类型值;(2)return的值要被外界接收
// function fn(){
// var name = 'jinYu',
// age= 16;
// return {
// name: name,
// age: age
// }
// }
// var res = fn()
// 不销毁作用域
// 1. 返回一个引用的数据类型值
// 2. 返回的值需要被外界接受
// var num =2;
// function fn(){
// var num =1;
// return function(){
// console.log(num); // 1
// }
// return {}
// }
// var f = fn()
// f();
// 2. 如果当前作用域有个空间地址,被函数体外的东西占用着,那么这个栈内存就不能销毁;
// function fn(){
// // oLis[i].onclick = function(){
// // }
// // var obj = {};
// // obj.a = function(){
// // }
// }
// fn()
// 不销毁
// var obj = {
// num:1,
// fn:(function(){
// // 不销毁
// return function(){
// }
// })()
// }
// 不立即销毁
function fn(){
var a = 12;
return function(){
console.log(a)
}
}
fn()()
// 当外层大函数执行完成之后不能立即销毁,他要继续等待里面的小函数执行完成销毁之后,大函数在销毁