本文共 2560 字,大约阅读时间需要 8 分钟。
为了更好的来阐述栈和堆,我们先来了解一下数据类型
在js中数据类型主要分为以下两大类:基本类型:String,Number,Boolean,Null,Undefined,symbol,这6种基本数据类型它们是直接按值存放的,所以可以直接访问。
引用类型:Function,Array,Object,当我们需要访问这三种引用类型的值时,首先得从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。
栈(stack):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
堆(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
1、缓存方式区别
1.栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放; 2.堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。2、堆栈数据结构区别
堆(数据结构):堆可以被看成是一棵树,如:堆排序;
栈(数据结构):一种先进后出的数据结构。
var a = 10;var b =a;
是 a 先取出 10,copy 一份放到 b 里面,改变 a 的值,b 的值是不变的,再把 a=20;时 b 的值还是 10,不发生改变 var arr = [1,2];var arr1 =arr;arr.push(3);
答案:这往[1,2]放 3,arr 和 arr1 都是[1,2,3]
引用值是在栈内存里面放堆的地址,拷贝的也是地址,所以改变 arr,arr1 也变了
var arr = [1,2]; var arr1 =arr; arr = [1,3]; document.write(arr1)
答案:arr = [1,3];是新建了一个新的房间。arr1 是 1,2,现在是插入新引入值”房间”,
会在堆里面重新申请一间房,并指向新房间
1、浅度拷贝
var obj = { name : "asdas", sex : klm, age : 12}var obj1 = { }function clone(target, origin){ var target = target || { } for(var prop in origin){ target[prop] = origin[prop]; } return target;}clone(obj1, obj);
结果为:
可以看出,原始值的拷贝,是直接复制栈里面的数值,所以一个改变但另一个不改变,但要是有引用值的情况下,就会发生下面的现象var obj = { name : "asdas", sex : [1,2,3], age : 12}var obj1 = { }function clone(target, origin){ var target = target || { } for(var prop in origin){ target[prop] = origin[prop]; } return target;}clone(obj1, obj);
结果为:
可以看出,这种浅度克隆,原始值改变不会影响,但是引用值改变的时候,克隆出来的那个也会跟着改变,所以要想改变这种现象,就要使用深度克隆2、深度克隆
var obj = { name : "sadafs", sex : "adwas", age : 213, card : ['sadsa', 'das'], wife : { name : "asd", son : { name : "sad", } }}var obj1 = { } function deepClone(origin, target){ var target = target || { }, toStr = Object.prototype.toString, arrStr = "[object Array]"; for(var prop in origin){ if(origin.hasOwnProperty(prop)){ if(origin[prop] !== "null" && typeof(origin[prop]) == 'object'){ if (toStr.call(origin[prop]) == arrStr){ target[prop] = []; }else{ target[prop] = { }; } deepClone(origin[prop], target[prop]); }else{ target[prop] = origin[prop]; } } } return target;}
结果为:
这样就解决了克隆会继承的现象如果想要堆溢出,比较简单,可以循环创建对象或大的对象; 如果想要栈溢出,可以递归调用方法,这样随着栈深度的增加,JVM
(虚拟机)维持着一条长长的方法调用轨迹,直到内存不够分配,产生栈溢出。
转载地址:http://lxtzi.baihongyu.com/