作用域
作用域
作用域(Scope) 是可访问变量的集合,JavaScript中对象和函数也是变量。
子作用域可以访问父作用域,反过来则不行。
JavaScript 的作用域分以下三种:
- 全局作用域:脚本模式运行所有代码的默认作用域
- 模块作用域:模块模式中运行代码的作用域
- 函数作用域:由函数创建的作用域
此外,用 let
或 const
声明的变量属于额外的作用域:
- 块级作用域:由一对花括号(一个代码块)创建出来的作用域
闭包
在js中,实现外部作用域访问内部作用域中变量的方法叫做“闭包”。
要理解JavaScript的闭包是怎么形成的,就要了解JavaScript的垃圾回收算法
垃圾回收算法
垃圾回收算法主要依赖于引用的概念。
一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。
引用计数法
IE6、7使用的垃圾回收算法,是最初的算法,称为引用计数法。
此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。
如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。
但是,如果两个对象互相引用,就会不满足条件而一直不被回收。
标记清除算法
此算法把“对象是否不再需要”简化定义为“对象是否可以获得”。
算法假定设置一个叫做根(root)的对象(在 Javascript 里,根是全局对象)。
垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……
从根开始,垃圾回收器将找到所有可以获得的对象,并回收所有不能获得的对象。
所有现代浏览器都使用了标记清除垃圾回收算法。
闭包的形成
创建一个的闭包的示例代码如下:
var closure = (function outer(){
var outerNum = 1
return function inner(){
return outerNum
}
})()
示例中,outer()
执行一次后,不再被引用,应当被回收。
它的返回值是函数inner()
,赋值给了全局作用域的closure
变量,所以inner()
不会被回收。closure
引用inner()
,inner()
引用outerNum
,所以outerNum
不会被回收。
据此,尽管outer()
可以被回收了,其中定义的outerNum
不会被回收,这样就形成了闭包。
概况理解,闭包是实现外部作用域访问内部作用域中变量的方法。