scope作用域 、Closure闭包对象
可以借助chrome调式工具查看闭包对象

注意:function声明存在变量提升,所以22行已经存在闭包对象了;
闭包产生的条件:
- 函数嵌套;
- 嵌套的内部函数引用了外部函数的变量才会产生闭包对象(如果fn1内部fn2外部再定义一个var b='111’它不会在Closure里面);
- 执行外部函数(导出外部函数);
① 执行函数定义(声明)就产生了闭包(不需要调用外部函数)。
② 闭包其实就是内部函数,它也是包含被引用对象的变量。
③ 闭包的数量跟外部函数调用次数有关,而与内部函数的执行次数无关。

常见的闭包
- 函数作为另一个函数的返回值,将外部函数的返回值赋值给一个变量之后再调用

- 将函数作为实参传递给另一个函数调用

setTimeout内部的第一个参数callback是一个闭包,内部引用了外部函数的变量msg
闭包的作用
- 函数再执行完以后,函数内部声明的局部变量依旧存在内存中,未被回收(延长了局部变量的生命周期);
- 在函数外部可以直接访问(操作)函数内部的局部变量;暴露内部变量,暴露指定方法(内部函数),使得外部可以使用指定的方法读取或者操作内部变量。
- 闭包对象一直存在的原因:
fn2没有被引用,函数执行完会自动释放;fn3这个变量会自动释放,f指向fn3这个函数对象的地址,函数对象又关联着闭包对象,所以闭包对象不会被回收(有f还引用着它)。

闭包的生命周期
产生:嵌套内部函数声明完成时就会产生闭包对象
死亡:嵌套内部函数成为垃圾对象(null)
- 函数声明式定义内部函数

- 函数表达式(匿名函数)定义内部函数

闭包的应用
- 可以定义JS模块
具有特定功能的js文件,将所有数据和功能封装在函数内部(私有),只对外暴露一个内部函数或者包含多个内部函数的对象,模块的使用者,只需要通过调用模块中暴露的函数或者对象中的函数,来实现对应的功能。
定义模块:

使用方法

另一种定义模块的方法(立即执行函数):

使用方法:

再次优化:

闭包的缺点
- 问题:函数执行完后,函数内部的局部变量没有释放,占用内存事件长,容易导致内存泄漏(占用内存没有被及时释放)。
解决:少用闭包,及时释放内存,用完后赋值为null,让内部函数成为垃圾对象,回收闭包。

- 问题:当需要内存太大,超出剩余内存时,就会内存溢出(页面崩溃直接报错)

内存泄漏积累的多了就容易导致内存溢出。
常见的内存泄露
-
- 意外的全局变量,没有用var、let、const声明,直接赋值;
-
- 没有及时清理的定时器或回调函数
-
- 闭包
面试题

所以最终打印The Window

最终打印My Object

① a.fun(1) a.fun(2) a.fun(3) 没有产生新的闭包对象(没有新的引用指向闭包对象),一直用的是var=fun(0)产生的闭包对象,闭包内的变量是n,n是第一次传入的0。
② 每一次都返回新的对象,不断产生新的闭包对象,每一次都打印前一次传入的值(这个值是闭包对象里的值)。
③ 先生成c的闭包对象(打印undefined和0),之后一直用c里面的闭包对象,里面存着上一次的传入值1。
//fun(0) 打印undefined
{fun:function(m){return fun(m,0)}
}
//a.fun(1)
function(1){
return fun(1,0)
}fun(1,0){
console.log(0);//0return {fun:function(m){return fun(m,1)}}
}
第一行打印undefined,0,0,0
//fun(0) 打印undefined
{fun:function(m){return fun(m,0)}
}//fun(0).fun(1) ⇒ fun(1,0)
fun(1,0){
console.log(0);//0return {fun:function(m){return fun(m,1)}}
}//fun(0).fun(1).fun(2) ⇒ fun(2,1)
fun(2,1){
console.log(1);//1return {fun:function(m){return fun(m,2)}}
}//fun(0).fun(1).fun(2).fun(3) ⇒ fun(3,2)
fun(3,2){
console.log(2);//2return {fun:function(m){return fun(m,3)}}
}
第二行打印undefined,0,1,2
//fun(0) 打印undefined
{fun:function(m){return fun(m,0)}
}//c = fun(0).fun(1) ⇒ fun(1,0)
fun(1,0){
console.log(0);//0return {fun:function(m){return fun(m,1)}}
}//c.fun(2) ⇒ fun(2,1)
fun(2,1){
console.log(1);//1return {fun:function(m){return fun(m,2)}}
}//c.fun(3) ⇒ fun(3,1)
fun(3,1){
console.log(1);//1return {fun:function(m){return fun(m,3)}}
}
第三行打印undefined,0,1,1
本篇文章为观看B站尚硅谷的视频讲解后的笔记,点击可快速跳转尚硅谷B站视频













![BUUCTF | [GXYCTF2019]BabySQli](https://img-blog.csdnimg.cn/1c495852653644bfa510f7b9716ef063.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bGx5bed57u_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16)



