Skip to content
导航

作用域

作用域

作用域(Scope) 是可访问变量的集合,JavaScript中对象和函数也是变量。
子作用域可以访问父作用域,反过来则不行。

JavaScript 的作用域分以下三种:

  • 全局作用域:脚本模式运行所有代码的默认作用域
  • 模块作用域:模块模式中运行代码的作用域
  • 函数作用域:由函数创建的作用域

此外,用 letconst 声明的变量属于额外的作用域:

  • 块级作用域:由一对花括号(一个代码块)创建出来的作用域

闭包

在js中,实现外部作用域访问内部作用域中变量的方法叫做“闭包”。

要理解JavaScript的闭包是怎么形成的,就要了解JavaScript的垃圾回收算法

垃圾回收算法

垃圾回收算法主要依赖于引用的概念。
一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。

引用计数法

IE6、7使用的垃圾回收算法,是最初的算法,称为引用计数法

此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。
如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。

但是,如果两个对象互相引用,就会不满足条件而一直不被回收。

标记清除算法

此算法把“对象是否不再需要”简化定义为“对象是否可以获得”。

算法假定设置一个叫做根(root)的对象(在 Javascript 里,根是全局对象)。
垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……
从根开始,垃圾回收器将找到所有可以获得的对象,并回收所有不能获得的对象。

所有现代浏览器都使用了标记清除垃圾回收算法。

闭包的形成

创建一个的闭包的示例代码如下:

js
var closure = (function outer(){
  var outerNum = 1
  return function inner(){
    return outerNum
  }
})()

示例中,outer()执行一次后,不再被引用,应当被回收。
它的返回值是函数inner(),赋值给了全局作用域的closure变量,所以inner()不会被回收。
closure引用inner()inner()引用outerNum,所以outerNum不会被回收。

据此,尽管outer()可以被回收了,其中定义的outerNum不会被回收,这样就形成了闭包。

概况理解,闭包是实现外部作用域访问内部作用域变量的方法。

参考资料