js作用域链和闭包(三)
闭包
概念:有权访问另一个作用域的函数.
作用:
1.可以读取自身函数外部的变量. (沿着作用域链查找)
2.让这些外部变量始终保存在内存中.
创建闭包的常见方式,就是在一个函数内部创建另一个函数.在内部定义的函数会将父函数的活动对象添加到他的作用域链中.
eg:
不闭包
1 | function fun (){ |
局部变量当函数运行完以后就会销毁这个变量,假如有多次调用这个函数它下一次调用的时候又会重新创建那个变量.
当调用fun()
,执行流进入该函数,创建一个执行环境,压入执行栈中,当函数中的代码执行完毕,环境栈将其弹出,把控制权交给下个执行环境.保存在执行环境中的作用域链中的所有变量和函数也随之销毁.
闭包
1 | function a (){ |
这里在函数a()
的内部定义了一个函数b()
,并return
了回去,同时在函数a
的外部定义了一个变量c
并引用了函数a
。这时候发现第二次执行c()
的时候输出为7,这说明在执行过一次的时候,变量num没有被销毁.
JavaScript中有回收机制,函数在被执行完以后这个函数的作用域就会被销毁,如果一个函数被其他变量引用,这个函数的作用域将不会被销毁.
那么来看看到底是如何引用的.
当a()
执行结束,内部函数开始被调用;a
的执行环境等待被回收,a
的作用域链对全局变量对象和a
的活动对象引用都断了。但是内部函数b()
保持着对a()
函数活动对象的引用,而b()
又保存在全局变量c
中,因此这些活动对象都不会被销毁。
当时有个疑问,那就是b的作用域链是什么时候建立的,才能有对a()
函数互动对象的引用.
一番查找,说是在调用a()
的时候,b
函数的作用域链就已经被初始化了.(复制父函数的作用域链,在推入自己的活动对象).
最后总结可以确定闭包的形成需要两个条件:
1.在函数内部创建新的函数.
2.新的函数在执行时,访问了函数的变量对象;