堆棧
堆(heap)和棧(stack)
堆: 為程序員動態(tài)分配的內(nèi)存,大小不定也不會自動釋放,特點是先進先出;
棧: 為自動分配的空間,它由系統(tǒng)自動釋放,特點是后進后出。
基本數(shù)據(jù)類型存放于棧內(nèi)存中,Undefined Null String Number Boolean,它們是直接按值存放的,可以直接訪問。
引用數(shù)據(jù)類型存放于堆內(nèi)存中,變量只是保存的一個指針,該指針指向堆內(nèi)存中的地址,當訪問引用類型數(shù)據(jù)(Array、Object、Function等)時,先從棧中獲得該對象的指針,再從堆中取出對象的數(shù)據(jù)。
值傳遞和地址傳遞
var a = 10;
var b = a;
b = 20;
console.log(a,b);
//以上的代碼修改 b 的值并不會影響 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]
//以上代碼可以看出 當改變 b 中的數(shù)據(jù)時,a 中的數(shù)據(jù)也發(fā)生了變化;改變 c 的 數(shù)據(jù)時,a 不會受影響
//a 是數(shù)組,屬引用類型,當將 a 賦值給 a 時,傳遞的是棧中的地址,而不是堆內(nèi)存中的對象。
//而 c 只是從 a 堆內(nèi)存中獲取的一個數(shù)據(jù)值,保存于棧中。修改 c 時,是在棧中直接修改
深拷貝與淺拷貝
在定義引用數(shù)據(jù)類型時,變量存放的只是一個地址。當使用對象拷貝,傳遞的也只是一個地址。因此在訪問拷貝對象屬性時,會根據(jù)地址找到源對象指向的堆內(nèi)存中。
淺拷貝
淺拷貝.PNG
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: [ '北京', '昌平' ] }
深拷貝
深拷貝.PNG
var obj1 = {
name : "zhar",
desc : ["北京"]
}
function copy(obj,target){
var newObj = target || {};
console.log(obj)
for(var key in obj){
//判斷是不是引用數(shù)據(jù)類型,即是不是對象
if(typeof obj[key] === "object"){
newObj[key] = (obj[key].constructor===Array)?[]:{};
//第二次調(diào)用時,要傳入target即newObj[key],newObj[key]要重復使用
copy(obj[key],newObj[key]);
}else{
newObj[key] = obj[key];
}
}
return newObj;
}
var obj2 = copy(obj1);
深拷貝就是為了解決淺拷貝時數(shù)據(jù)互相影響而存在的
垃圾回收
Javascript 具有自動垃圾回收機制,執(zhí)行環(huán)境會管理代碼執(zhí)行過程中使用的內(nèi)存。
使我們不必像 C 或 C++開發(fā)者那樣,手動去管理內(nèi)存的釋放。
自動回收機制原理:
垃圾回收器按照固定的時間間隔找出不再繼續(xù)使用的變量,然后釋放其占用的內(nèi)存。
兩種策略:
- 標記清除(現(xiàn)在瀏覽器都在使用)
最常用的垃圾回收方式。當變量進入環(huán)境時,將變量標記為"進入環(huán)境";當變量離開環(huán)境時,將其標記為"離開環(huán)境"。
到2008年,各瀏覽器使用的清除策略都是標記清除,差別在于時間間隔不同 - 引用計數(shù)(已被棄用)
引用計數(shù)是跟蹤每個值被引用的次數(shù);當有一個變量被引用時,則這個值的引用次數(shù)加1,當取消一個引用時,次數(shù)減1。當引用值變?yōu)? 時,將由垃圾收集器回收
引用計數(shù)方式有嚴重的問題,就是,當變量相互引用時,如:
var obj1 = {}
var obj2 = {}
obj1.a = obj2;
obj2.b = obj1;
對于上面的代碼,存在相互引用,其引用計數(shù)永遠為2,就會導致對象永遠不會被回收。
前端程序員最簡單粗暴的釋放內(nèi)存的方式:
obj = null;