堆棧內存的區別
堆棧內存的區別(看圖)
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()()
// 當外層大函數執行完成之後不能立即銷燬,他要繼續等待裏面的小函數執行完成銷燬之後,大函數在銷燬