现在的随着前端开发者如雨后春笋般的诞生,越来越多的项目落地,JavaScript是我们前端开发中必不可少的一环。今天让我们来了解一下JavaScript中的堆栈原理
明白的堆栈原理之后也可以让我们的代码更加的贴近编译器,更加的明白系统对内存的分配, 帮助我们能够更好的管理内存
堆和栈是我们常用的数据结构,还有图,树,链表等,感兴趣的可以读一下数据结构-百度百科
两者都是存放临时数据的地方。
栈区(stack
) 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
堆区(heap
) 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
堆(数据结构):堆可以被看成是一棵树,如:堆排序; 栈(数据结构):一种先进后出的数据结构。相反的队列就是一种先进先出的数据结构
undefined,null,布尔值(Boolean),字符串(String),数值(Number)
var a = 1
var b = a
console.log(a) // 1
console.log(b) // 1
a = 3
console.log(a) // 3
console.log(b) // 1
上面代码实际上是为a
在栈中创建了一个值,第二句把一个变量向一个变量复制时,会在栈中创建一个新值,然后把值复制到为新变量分配的位置上。
变量 | 值 |
---|---|
a | 1 |
b | 1 |
重新为a
赋值后
变量 | 值 |
---|---|
a | 3 |
b | 1 |
统称为Object类型,细分的话,有:Object类型,Array类型,Date类型,Function类型等。
var obj = {}
obj.a = 1
var copyObj = obj
console.log(obj) // {a: 1}
obj.a = 2
console.log(obj) // {a: 2}
console.log(copyObj) // {a: 2}
上面的第一句在栈中为obj
创建了一个值,并且在堆中为obj
分配了一个地址,第三句我们在栈中创建了一个copyObj
,此时他的地址也指向了堆中的这个地址,改变obj
或者copyObj
的属性两者都会发生改变,他们在堆中公用一个内存地址
此时我们是否可以理解堆栈溢出
堆栈溢出就是不顾堆栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界,结果覆盖了别的数据。 可以理解为 在长字符串中嵌入一段代码,并将过程的返回地址覆盖为这段代码的地址,这样当过程返回时,程序就转而开始执行这段自编的代码了。
就是你的变量定义过多了,占用内存过多了,浏览器或者操作系统已经不能容忍你了
在定义一个对象或数组时,变量存放的往往只是一个地址。当我们使用对象拷贝时,如果属性是对象或数组时,这时候我们传递的也只是一个地址。因此子对象在访问该属性时,会根据地址回溯到父对象指向的堆内存中,即父子对象发生了关联,两者的属性值会指向同一内存空间。
var a = {
key1:"11111"
}
function Copy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
return c;
}
a.key2 = ['小辉','小辉'];
var b = Copy(a);
b.key3 = '33333';
alert(b.key1); // 1111111
alert(b.key3); // 33333
alert(a.key3); // undefined
a对象中key1属性是字符串,key2属性是数组。a拷贝到b,12属性均顺利拷贝。给b对象新增一个字符串类型的属性key3时,b能正常修改,而a中无定义。说明子对象的key3(基本类型)并没有关联到父对象中,所以undefined。
常见的实现方式
Object.assign({}, 要拷贝的对象)
jquery
的extend
方法lodash
中的方法深拷贝会为原对象和拷贝对象从新在栈和堆中分配一个地址,两者之间的操作互不影响
常用的实现方式
jquery
中的extend
方法lodash
的_.deep(obj)
JSON.parse(JSON.stringify(obj))
深浅拷贝 的主要区别就是:复制的是引用(地址)还是复制的是实例。
参考