1

前言

上篇 【闯关模式】作用域、链和闭包 中

任务四 闭包(Closures)

闭包在JS中是很重要的概念,他们让JS出色地完成异步任务。

为了能更好的理解闭包,我们先来看作用域链的例子:

someFunc()
    ↑
    |
 inner()
    ↑
    |
  foo()

我们称someFunc()声明了一个变量bar:

someFunc()
 var bar
    ↑
    ⋮

有了嵌套作用域的知识,我们可以说inner()有权访问bar:

someFunc()
 var bar
    ↑
    |
 inner()
alert(bar)
    ↑
    ⋮

inner() 可以说 包住了 bar. 所以 inner() 是一个 闭包 .

为了回调式的编程,即使inner()不立即执行,闭包也会保持。在JS中将inner传来传去,或者稍后在someFunc()中返回出来也是可以的,而在这个过程中,bar将一直是可用的。


你的任务

修改之前的代码,设置zip()中的bar = true,然后在foo()中将zip return出来。

完成后, 执行scope-chains-closures verify <your-file.js>来验证你的答案

任务五 垃圾回收机制 (Garbage Collection)

在JS中,内存是被运行时环境(runtime)自动管理的。运行时环境决定了已用内存的释放。而这个决策过程就称之为 垃圾回收机制

每一个JS运行环境都有自己的垃圾回收机制的算法,但是大多数用的都类似:标记&清除算法,这个算法的原理即:
只标记活动代码中可达的内存的引用(变量,函数等),任何引用只要没有被标记,就会被垃圾回收掉(即该块内存被释放掉)

而这个标记可达内存的概念也一定程度上和闭包有关:

 someFunc()
  var bar
return inner
     ↑
     |
  inner()
 alert(bar)
     ↑
     ⋮

当闭包inner()someFunc()return掉,它仍然保持了对bar的引用,这时标记&清除算法就会标记bar可达,因此bar也就不会被垃圾回收掉。

inner()来说,为了能正确解析对bar的引用,不仅需要保持存放bar的这块内存,而且需要保持可以访问到bar的这条作用域链。

一旦对inner()的引用不再需要,就可以对其进行垃圾回收了,这也意味着bar也可以被垃圾回收,最终整条作用域链都被回收掉,内存被释放。

所以说,作用域,作用域链,闭包,垃圾回收机制,他们都是息息相关的!


你的任务

你需要用Chrome的DevTools来检验垃圾回收机制的运行。按以下的步骤来感受一下垃圾回收:

1) 在Chrome中开一个tab
2) 打开DevTools > Timeline tab
3) 确保设置和下图一致:
a) 取消选中 Frames View (allows seeing memory graphs)
b) 选中 Flame Chart View (allows seeing where execution time is spent)
c) 选项中只选择 "Memory"
4) 点击灰色圆形按钮开始搜集数据
5) 随便访问一个网站http://www.baidu.com
6) 点击红色的录制按钮停止搜集数据
7) 然后你家能看到类似下图:
8) 我们要关注的是内存突然减少的地方:
9) 选择这部分突然减少的内存
10) 看那个叫"GC Event"的黄色部分:
11) 然后就能看到回收的总内存量和耗时

有趣的事情是,GC的耗时:一般远远超过16ms(这个能保持60fps的最大值)。同时当GC发生时会阻塞主线程,所以如果你的程序很卡,就可能是大量GC惹的祸。

Note: 你如果有强迫症,也可以继续运行 scope-chain-closures verify

翻译仓促,如有错误欢迎指出!点赞更好哦~

附录

闯关项目地址


savokiss
6.2k 声望4.5k 粉丝

You know nothing, SpongeBob.