现在的随着前端开发者如雨后春笋般的诞生,越来越多的项目落地,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))
- 其他
深浅拷贝 的主要区别就是:复制的是引用(地址)还是复制的是实例。
参考
- 知乎
- 百度百科
- CSDN
- 其他