思维导图
![](https://img-blog.csdnimg.cn/1638a0900c834aaa85cbf7857b7585b2.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6LS-5YWs5a2QMjc1,size_20,color_FFFFFF,t_70,g_se,x_16)
堆栈内存小科普
1)js中的内存分为:堆内存和栈内存
【堆内存】:只要用来存储引用数据类型的值(对象存的是键值对,函数存的是字符串)
【栈内存】:供js运行的环境(函数执行),存基本数据类型的值
堆栈内存的释放问题
我们每次给变量存值或者执行函数的时候都会占用内存空间,如果一直这样下去,日积月累,电脑总会装不下的,所以内存是需要释放的。
1)堆内存的释放:
常见的浏览器释放方式主要有以下两种:
- 谷歌浏览器是标记方式,每隔一段时间就会检测以下当前作用域中的内存,是否被占用,如果没有被占用,就会释放掉。
- ie和火狐等浏览器是采用计数方法,当前作用域中如果一个空间地址被占用一次,就会累加一,如果减少一次占用就会减1,直到0的时候,说明已经没有被占用了,就释放了。
堆内存释放:让所有引用这个堆内存的变量赋值为null,堆内存地址不在被占用,浏览器在空闲的时候就会把堆内存 释放
2)栈内存释放:
- 销毁:全局栈内存,只有当页面关闭的时候才会被释放
- 销毁:函数执行完成,一般情况下都会被销毁掉
- 不销毁:当前作用域中如果有一个引用数据类型的值被外面的变量占用就不销毁
- 不立即销毁,(当函数执行完毕之后销毁)
闭包
回忆变量作用域
根据作用域的不同分为两种,全局变量和局部变量
- 1.函数内部可以使用全局变量
- 2.函数外部不可以使用局部变量
- 3.当函数执行完毕,本作用域的局部变量会销毁
什么是闭包?
闭包指有权访问内一个函数作用域中变量的函数,一个作用域可以访问另外一个函数内部的局部变量
闭包形成的原因?
内部函数存在外部作用域的引用就会导致闭包
子函数fo内存存在外部作用域的ab,所以这里产生了闭包
var a = 0
function foo() {
var b = 14
function fo() {
console.log(a, b)
}
fo()
}
foo()
注意闭包中的变量存储的位置是堆内存中
闭包的作用
- 【保护】:保护里面的私有变量不受外界的干扰.
- 【保存】:形成不销毁的作用域,可以把里面的变量保存下来,
闭包在实战中的应用
return回一个函数, f()就是一个闭包,存在上级作用域的引用
var n = 10
function fn() {
var n = 20
function f() {
n++;
console.log(n)
}
return f
}
var x = fn()
x() // 21
自执行函数同样产生闭包
立即执行函数也是小闭包 因为立即执行函数里面任何一个函数都可以他的i变量
for (var i = 0; i < lis.length; i++) {
//利用for循环创建了4个立即执行函数
//立即执行函数也是小闭包 因为立即执行函数里面任何一个函数都可以他的i变量
(function (i) {
lis[i].onclick = function () {
console.log(i);
}
})(i)
使用闭包需要注意什么?
容易导致内存泄漏。闭包会携带包含其它的函数作用域,因此会比其他函数占用更多的内存。过度使用闭包会导致内存占用过多,所以要谨慎使用闭包。
浏览器的垃圾回收机制GC
浏览器的内存回收机制:浏览器在空闲的时候,会把所有未被占用的内存释放掉,以此优化内存空间,对于前端开发来讲,我们应该尽可能的减少内存的开辟,并且把一些无用内存取消对其的占用
全局上下文:打开页面,执行全局代码就会形成;只有当页面关闭的时候才会释放;f5刷新页面
会把上一次的释放,在形成一个新的
私有上下文:一般函数(代码块)中的代码执行完,浏览器会自动把私有上下文出栈释放;但是如果,当前上下文中,某个和它关联的内容(一般指的是一个堆内存)被当前上下文以外的事物占用了,那么这个私有上下文不能出栈释放;这样私有上下文中的“私有变量/值”也被保存起来了!
闭包的机制:函数执行产生一个不被释放的上下文,这样不仅函数中的私有变量不受外界的干扰(保护),而且存储的信息也不会被释放掉(保存,可以供其下级上下文调取使用)我们把这种保护加保存的机制称之为闭包
栗子
10+(++n) 先n累加1,累加后的结果再去和10运算
10+(n++)先拿n的值和10运算,运算完再把n++
let x = 5;
const fn = function fn(x) {
return function (y) {
console.log(y + (++x));
}
}
let f = fn(6);
f(7);//14
fn(8)(9);//18
f(10);//18
console.log(x);//5
图解
![](https://img-blog.csdnimg.cn/529e20556bef4b069eaea62d045a0b0c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YmN56uvIOi0vuWFrOWtkA==,size_20,color_FFFFFF,t_70,g_se,x_16)
栗子2
函数重构:第一次执行把A赋值为里面的小函数
let a=0,
b=0;
function A(a){
A=function(b){
alert(a+b++);
};
alert(a++);
}
A(1);//1
A(2);//4
图解
![](https://img-blog.csdnimg.cn/09caaa9aa0fb4bb8a36a92bcf8a69151.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YmN56uvIOi0vuWFrOWtkA==,size_20,color_FFFFFF,t_70,g_se,x_16)
-----------------------------------------------------完结------------------------------------------------------------------
--------------------------接受大佬们的批改, 欢迎评论留言-----------------------------------------------------------