先解释一下什么是“自由变量”。

在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量。如下图

如上程序中,在调用fn()函数时,函数体中第6行。取b的值就直接可以在fn作用域中取,因为b就是在这里定义的。而取x的值时,就需要到另一个作用域中取。到哪个作用域中取呢?

有人说过要到父作用域中取,其实有时候这种解释会产生歧义。例如:

所以,不要在用以上说法了。相比而言,用这句话描述会更加贴切——要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”,切记切记——其实这就是所谓的“静态作用域”。

对于本文第一段代码,在fn函数中,取自由变量x的值时,要到哪个作用域中取?——要到创建fn函数的那个作用域中取——无论fn函数将在哪里调用。

上面描述的只是跨一步作用域去寻找。

如果跨了一步,还没找到呢?——接着跨!——一直跨到全局作用域为止。要是在全局作用域中都没有找到,那就是真的没有了。

这个一步一步“跨”的路线,我们称之为——作用域链。

我们拿文字总结一下取自由变量时的这个“作用域链”过程:(假设a是自由量)

第一步,现在当前作用域查找a,如果有则获取并结束。如果没有则继续;

第二步,如果当前作用域是全局作用域,则证明a未定义,结束;否则继续;

第三步,(不是全局作用域,那就是函数作用域)将创建该函数的作用域作为当前作用域;

第四步,跳转到第一步。

以上代码中:第13行,fn()返回的是bar函数,赋值给x。执行x(),即执行bar函数代码。取b的值时,直接在fn作用域取出。取a的值时,试图在fn作用域取,但是取不到,只能转向创建fn的那个作用域中去查找,结果找到了。

这一节看似很轻松的把作用域链引出来,并讲完了。之所有轻松是有前几节的基础,否则将很难解释。

接下来咱们开始正式说说一直期待依旧的朋友——闭包。敬请期待下一节。

---------------------------------------------------------------------------

本文已更新到《深入理解javascript原型和闭包系列》的目录,更多内容可参见《深入理解javascript原型和闭包系列》。

另外,欢迎关注我的微博

也欢迎关注我的其他教程:

用grunt搭建自动化的web前端开发环境从设计到模式》《json2.js源码解读视频》《微软petshop4.0源码解读视频

--------------------------------------------------------------------------

最新文章

  1. Java 集合与队列的插入、删除在并发下的性能比较
  2. Android学习笔记(十一)——ListView的使用(下)
  3. React Native交互组件之Touchable
  4. Windows命令行重命名文件
  5. Linux之free命令
  6. ios Object Encoding and Decoding with NSSecureCoding Protocol
  7. HTML5简易在线画图工具
  8. struts2整合spring的思路
  9. STL中主要的算法(一)
  10. angular.js封装的树形指令
  11. BZOJ 2342: [Shoi2011]双倍回文 [Manacher + set]
  12. VS 2017 开发安卓环境搭建 问题总结
  13. Docker创建 tomcat/weblogic 集群
  14. 3U - 算菜价
  15. [主席树 强制在线]ZOJ3888 Twelves Monkeys
  16. PHP文件解密服务,微擎微赞模块解密,微擎模块解密
  17. sqlzoo需要知道的那些事
  18. Linux 查看服务器配置
  19. PHP中多IP段权限控制方案
  20. Linux中安装配置spark集群

热门文章

  1. Centos允许root远程登录设置
  2. makefile之VPATH和vpath的使用
  3. [原]经典bootstrap模态框使用文章
  4. 极客DIY:打造你的专属黑客U盘
  5. 【2016-10-31】【坚持学习】【Day16】【MongoDB】【入门】
  6. 利用Caffe做回归(regression)
  7. NOIP2013pj车站分级[拓扑排序]
  8. 验证LeetCode Surrounded Regions 包围区域的DFS方法
  9. SQL 语句大全(转载)
  10. .NET Core 1.0 RC2 历险之旅