堆棧
堆(heap)和棧(stack)
堆: 為程序員動(dòng)態(tài)分配的內(nèi)存悲酷,大小不定也不會(huì)自動(dòng)釋放粟关,特點(diǎn)是先進(jìn)先出疮胖;
棧: 為自動(dòng)分配的空間,它由系統(tǒng)自動(dòng)釋放闷板,特點(diǎn)是后進(jìn)后出获列。
基本數(shù)據(jù)類型存放于棧內(nèi)存中,Undefined Null String Number Boolean蛔垢,它們是直接按值存放的击孩,可以直接訪問。
引用數(shù)據(jù)類型存放于堆內(nèi)存中鹏漆,變量只是保存的一個(gè)指針巩梢,該指針指向堆內(nèi)存中的地址创泄,當(dāng)訪問引用類型數(shù)據(jù)(Array、Object括蝠、Function等)時(shí)鞠抑,先從棧中獲得該對(duì)象的指針,再從堆中取出對(duì)象的數(shù)據(jù)忌警。
值傳遞和地址傳遞
var a = 10;
var b = a;
b = 20;
console.log(a,b);
//以上的代碼修改 b 的值并不會(huì)影響 a 的值
var a = [1,2,3,4];
var b = a;
var c = a[0];
console.log(b);
console.log(c);
b[0] = 9;
c = 10;
console.log(a);//[9,2,3,4]
//以上代碼可以看出 當(dāng)改變 b 中的數(shù)據(jù)時(shí)搁拙,a 中的數(shù)據(jù)也發(fā)生了變化;改變 c 的 數(shù)據(jù)時(shí)法绵,a 不會(huì)受影響
//a 是數(shù)組箕速,屬引用類型,當(dāng)將 a 賦值給 a 時(shí)朋譬,傳遞的是棧中的地址盐茎,而不是堆內(nèi)存中的對(duì)象。
//而 c 只是從 a 堆內(nèi)存中獲取的一個(gè)數(shù)據(jù)值徙赢,保存于棧中字柠。修改 c 時(shí),是在棧中直接修改
深拷貝與淺拷貝
在定義引用數(shù)據(jù)類型時(shí)狡赐,變量存放的只是一個(gè)地址窑业。當(dāng)使用對(duì)象拷貝,傳遞的也只是一個(gè)地址枕屉。因此在訪問拷貝對(duì)象屬性時(shí)常柄,會(huì)根據(jù)地址找到源對(duì)象指向的堆內(nèi)存中。
淺拷貝
var obj1 = {
name : "zhar",
desc : ["北京"]
}
function copy(o1){
var newObj = {};
for(var key in o1){
newObj[key] = o1[key];
}
return newObj;
}
// var obj2 = obj1;
var obj2 = copy(obj1);
obj2.name = "tom";
obj2.desc.push("昌平");
console.log(obj1);//{ name: 'zhar', desc: [ '北京', '昌平' ] }
深拷貝
var obj1 = {
name : "zhar",
desc : ["北京"]
}
function copy(obj,target){
var newObj = target || {};
console.log(obj)
for(var key in obj){
//判斷是不是引用數(shù)據(jù)類型搀庶,即是不是對(duì)象
if(typeof obj[key] === "object"){
newObj[key] = (obj[key].constructor===Array)?[]:{};
//第二次調(diào)用時(shí)拐纱,要傳入target即newObj[key]铜异,newObj[key]要重復(fù)使用
copy(obj[key],newObj[key]);
}else{
newObj[key] = obj[key];
}
}
return newObj;
}
var obj2 = copy(obj1);
深拷貝就是為了解決淺拷貝時(shí)數(shù)據(jù)互相影響而存在的
垃圾回收
Javascript 具有自動(dòng)垃圾回收機(jī)制哥倔,執(zhí)行環(huán)境會(huì)管理代碼執(zhí)行過程中使用的內(nèi)存。
使我們不必像 C 或 C++開發(fā)者那樣揍庄,手動(dòng)去管理內(nèi)存的釋放咆蒿。
自動(dòng)回收機(jī)制原理:
垃圾回收器按照固定的時(shí)間間隔找出不再繼續(xù)使用的變量,然后釋放其占用的內(nèi)存蚂子。
兩種策略:
- 標(biāo)記清除(現(xiàn)在瀏覽器都在使用)
最常用的垃圾回收方式沃测。當(dāng)變量進(jìn)入環(huán)境時(shí),將變量標(biāo)記為"進(jìn)入環(huán)境"食茎;當(dāng)變量離開環(huán)境時(shí)蒂破,將其標(biāo)記為"離開環(huán)境"。
到2008年别渔,各瀏覽器使用的清除策略都是標(biāo)記清除附迷,差別在于時(shí)間間隔不同 - 引用計(jì)數(shù)(已被棄用)
引用計(jì)數(shù)是跟蹤每個(gè)值被引用的次數(shù)惧互;當(dāng)有一個(gè)變量被引用時(shí),則這個(gè)值的引用次數(shù)加1喇伯,當(dāng)取消一個(gè)引用時(shí)喊儡,次數(shù)減1。當(dāng)引用值變?yōu)? 時(shí)稻据,將由垃圾收集器回收
引用計(jì)數(shù)方式有嚴(yán)重的問題艾猜,就是,當(dāng)變量相互引用時(shí)捻悯,如:
var obj1 = {}
var obj2 = {}
obj1.a = obj2;
obj2.b = obj1;
對(duì)于上面的代碼匆赃,存在相互引用,其引用計(jì)數(shù)永遠(yuǎn)為2秋度,就會(huì)導(dǎo)致對(duì)象永遠(yuǎn)不會(huì)被回收炸庞。
前端程序員最簡單粗暴的釋放內(nèi)存的方式:
obj = null;