闭包
闭包的概念
- 函数执行产生一个私有上下文,这里的私有的变量被“保护”起来,不受外界干扰!如果上下文不被释放,则里面的私有变量会被“保存”下来,这样其下级上下文就可以操作(访问)这些值!
- 把这种“保护 + 保存”的机制,称之为闭包
let a = 0,b = 0;
let A = function (a) { // 执行A会重构自己
A = function(b) { // A不是自己的,是全局的,此操作是修改全局A的地址,A指向的堆不会被释放,其上下文也不会被释放;需要A=null手动释放
alert(a + b++)
}
console.log(A);
alert(a++)
}
// 结论:不一定函数返回函数才产生闭包,闭包是一种 机制!
console.log(1, A);
A(1)
A(2)
闭包作用域
-
相关名词
EC(G):全局执行上下文
VO(G):全局变量对象(存储全局上下文生成的变量)(windo 指向 GO)
GO:堆内存开辟的空间,存储浏览器内置 api(var、function 声明的值放在这) -
浏览器的垃圾回收(内存释放)机制
- 堆内存:看当前堆内存空间的地址是否被别的东西占用
没有占用:浏览器会在空闲时释放这个堆内存; 占用:不能被释放
- 栈内存
EG(G) 打开页面的时候形成,页面关闭才会释放
函数/块级私有上下文// 正常情况下,代码执行完,产生的私有上下文会被释放 // 特殊情况,如果上下文创建的某个东西(一般是指函数)被上下文以外的事物占用了,则不仅这个东西不能被释放,而且当前这个私有上下文也不能被释放 let x = 5 const fn = function fn () { return function(y) { console.log(y + (++x)); } } let f = fn(6) f(7) fn(7)(8)
匿名函数
- 自执行函数
(function () { })()
匿名函数具名化
|特点:
- 不会在所处上下文环境(宿主环境)中进行声明
- 在自己执行产生的上下文中会被声明赋值,值是函数本身
- 声明赋的值默认是不能修改的
(function fn() { fn = 1 // let fn = 1 console.log(fn); // 函数本身 })
- 匿名函数实现递归
'use strict' let num = 0; (function fn() { if (num >= 5) return num++ // arguments.callee 获取的是函数本身(严格模式下不允许使用) // arguments.callee() fn() })() console.log(num);
闭包应用场景
- 数据封装
控制变量的访问权限,只暴露需要的接口。这种封装机制可以防止外部代码直接访问和修改内部数据
- 模块化编程
将相关的变量和函数放在在一个闭包内部,形成模块。可以避免全局命名冲突,提供命名空间,并且允许模块内部的函数相互调用和共享数据
- 回调函数
闭包可以捕获外部函数的上下文,并在内部函数被调用时保留这个上下文,从而实现对异步操作的响应
- 缓存和记忆
可以在函数内部维护一个缓存,避免重复计算相同的结果,提高函数执行的性能
🌟🌟🌟