堆栈和垃圾回收

堆栈

堆(heap)和栈(stack)
堆: 为程序员动态分配的内存,大小不定也不会自动释放,特点是先进先出;
栈: 为自动分配的空间,它由系统自动释放,特点是后进后出。

基本数据类型存放于栈内存中,Undefined Null String Number Boolean,它们是直接按值存放的,可以直接访问。

引用数据类型存放于堆内存中,变量只是保存的一个指针,该指针指向堆内存中的地址,当访问引用类型数据(Array、Object、Function等)时,先从栈中获得该对象的指针,再从堆中取出对象的数据。

值传递和地址传递

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 中的数据时,a 中的数据也发生了变化;改变 c 的 数据时,a 不会受影响
//a 是数组,属引用类型,当将 a 赋值给 a 时,传递的是栈中的地址,而不是堆内存中的对象。
//而 c 只是从 a 堆内存中获取的一个数据值,保存于栈中。修改 c 时,是在栈中直接修改

深拷贝与浅拷贝

在定义引用数据类型时,变量存放的只是一个地址。当使用对象拷贝,传递的也只是一个地址。因此在访问拷贝对象属性时,会根据地址找到源对象指向的堆内存中。

浅拷贝

堆栈和垃圾回收_第1张图片
浅拷贝.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: [ '北京', '昌平' ] }

深拷贝

堆栈和垃圾回收_第2张图片
深拷贝.PNG
var obj1 = {
    name : "zhar",
    desc : ["北京"]
}
function copy(obj,target){
    var newObj = target || {};
    console.log(obj)
    for(var key in obj){
    //判断是不是引用数据类型,即是不是对象
        if(typeof obj[key] === "object"){
            newObj[key] = (obj[key].constructor===Array)?[]:{};
//第二次调用时,要传入target即newObj[key],newObj[key]要重复使用
            copy(obj[key],newObj[key]);
        }else{
            newObj[key] = obj[key];
        }
    }
    return newObj;
}
var obj2 = copy(obj1);

深拷贝就是为了解决浅拷贝时数据互相影响而存在的

垃圾回收

Javascript 具有自动垃圾回收机制,执行环境会管理代码执行过程中使用的内存。

使我们不必像 C 或 C++开发者那样,手动去管理内存的释放。

自动回收机制原理:

垃圾回收器按照固定的时间间隔找出不再继续使用的变量,然后释放其占用的内存。

两种策略:

  1. 标记清除(现在浏览器都在使用)
    最常用的垃圾回收方式。当变量进入环境时,将变量标记为"进入环境";当变量离开环境时,将其标记为"离开环境"。
    到2008年,各浏览器使用的清除策略都是标记清除,差别在于时间间隔不同
  2. 引用计数(已被弃用)
    引用计数是跟踪每个值被引用的次数;当有一个变量被引用时,则这个值的引用次数加1,当取消一个引用时,次数减1。当引用值变为0 时,将由垃圾收集器回收
    引用计数方式有严重的问题,就是,当变量相互引用时,如:
var obj1 = {}
var obj2 = {}
obj1.a = obj2;
obj2.b = obj1;

对于上面的代码,存在相互引用,其引用计数永远为2,就会导致对象永远不会被回收。

前端程序员最简单粗暴的释放内存的方式:

obj = null;

你可能感兴趣的:(堆栈和垃圾回收)