关于闭包,初学者会被绕的晕头转向,在学习的路上也付出了很多精力来理解。 让我们一起来揭开闭包神秘的面纱。

闭包晦涩的定义

看过很多关于闭包的定义,很多讲的云里雾里,晦涩难懂。让不少人以为闭包是多么玄乎的东西。在我看过的所有书籍中,我更喜欢《你不知道的javascript(上卷)》的定义:

当函数可以记住并访问所在的词法作用域时,就产生了闭包,或者说函数在创建时的词法作域之外执行。

通俗的来说(不严谨): 就是函数套函数,子函数可以有权访问父函数的变量、父函数的父函数的变量、一直到全局变量。子函数如果不被销毁,整条作用域链上的变量仍然保存在内存中。

关于词法作用域,这里不做过多的解释,详情参考:http://www.cnblogs.com/ylweb/p/7531259.html.

下面用一些代码来解释这个定义:

function foo() {var a = 2;function bar() {console.log( a ); // 2}bar();
}foo();

严格来说这段代码并没有形成闭包,因为bar是在创建时所在的词法作用域执行。bar() 对a 的引用的方法是词法作用域的查找规则,而这些规则只是闭包的一部分。从学术的角度说:,在上面的代码片段中,函数bar() 具有一个涵盖foo() 作用域的闭包
(事实上,涵盖了它能访问的所有作用域,比如全局作用域)。也可以认为bar() 被封闭在
了foo() 的作用域中。为什么呢?原因简单明了,因为bar() 嵌套在foo() 内部。

下面我们来看一段代码,清晰地展示了闭包:

function foo() {var a = 2;function bar() {console.log( a );}return bar;
}var baz = foo();
baz(); // 2 —— 朋友,这就是闭包的效果。

函数bar() 的词法作用域能够访问foo() 的内部作用域。然后我们将bar() 函数本身当作一个值类型进行传递。在这个例子中,我们将bar 所引用的函数对象本身当作返回值。

在foo() 执行后,其返回值(也就是内部的bar() 函数)赋值给变量baz 并调用baz(),实际上只是通过不同的标识符引用调用了内部的函数bar()。

bar() 显然可以被正常执行。但是在这个例子中,它在自己定义的词法作用域以外的地方执行。

在foo() 执行后,通常会期待foo() 的整个内部作用域都被销毁,因为我们知道引擎有垃圾回收器用来释放不再使用的内存空间。由于看上去foo() 的内容不会再被使用,所以很自然地会考虑对其进行回收。

而闭包的“神奇”之处正是可以阻止这件事情的发生。事实上内部作用域依然存在,因此没有被回收。谁在使用这个内部作用域?原来是bar() 本身在使用。

拜bar() 所声明的位置所赐,它拥有涵盖foo() 内部作用域的闭包,使得该作用域能够一直存活,以供bar() 在之后任何时间进行引用。

bar() 依然持有对该作用域的引用,而这个引用就叫作闭包。

循环与闭包

以下是一个最常见的for循环例子:

for (var i=1; i<=5; i++) {setTimeout( function timer() {console.log( i );}, i*1000 );
}

正常情况下,我们对这段代码行为的预期是分别输出数字1~5,但实际上,这段代码在运行时输出五次6。 Why?

首先解释6 是从哪里来的。这个循环的终止条件是i 不再<=5。条件首次成立时i 的值是6。因此,输出显示的是循环结束时i 的最终值。

仔细想一下,这好像又是显而易见的,延迟函数的回调会在循环结束时才执行。事实上,当定时器运行时即使每个迭代中执行的是setTimeout(.., 0),所有的回调函数依然是在循环结束后才会被执行,因此会每次输出一个6 出来。

问题实质:

我们试图假设循环中的每个迭代在运行时都会给自己“捕获”一个i 的副本。但是根据作用域的工作原理,实际情况是尽管循环中的五个函数是在各个迭代中分别定义的,但是它们都被封闭在一个共享的全局作用域中,因此实际上只有一个i

改进方案:

for (var i=1; i<=5; i++) {(function(j) {setTimeout( function timer() {console.log( j );}, j*1000 );})( i );
}

ES6改进:

for (let i=1; i<=5; i++) {setTimeout( function timer() {console.log( i );}, i*1000 );
}

转载于:https://www.cnblogs.com/ylweb/p/7804309.html

JS闭包—你不知道的JavaScript上卷读书笔记(二)相关推荐

  1. 你不知道的JavaScript 上卷读书笔记

    看了<你不知道的JavaScript 上>,为了防止自己忘记,特此记下与我而言的部分重点 任何足够先进的技术都和魔法无异. --Arthur C. Clarke 作用域和闭包 编译原理 分 ...

  2. 【你不知道的JavaScript上卷】——作用域与闭包

    原文: [你不知道的JavaScript上卷]--作用域与闭包 JS语言万变不离其宗,其中最常用.最重要的也就是常用的几个大概念.数据类型.作用域.原型链.闭包.this指针.异步,不同的人理解不一样 ...

  3. JavaScript设计模式读书笔记(四)= 技巧型设计模式

    全系列目录 JavaScript设计模式读书笔记(一)=> 创建型设计模式 JavaScript设计模式读书笔记(二)=> 结构型设计模式 JavaScript设计模式读书笔记(三)=&g ...

  4. JavaScript设计模式读书笔记(一)= 创建型设计模式

    全系列目录 JavaScript设计模式读书笔记(一)=> 创建型设计模式 JavaScript设计模式读书笔记(二)=> 结构型设计模式 JavaScript设计模式读书笔记(三)=&g ...

  5. 你不知道的javascript上卷

    你不知道的javascript上卷 作用域 javascript是一门编译语言,它不是提前编译的,编译结果也不能在分布式系统中移植.编译的步骤一般如下: 分词/词法分析 词法分析是有状态的判断一个分词 ...

  6. oracle直查和call哪个更快,让oracle跑的更快1读书笔记二

    当前位置:我的异常网» 数据库 » <>读书笔记二 <>读书笔记二 www.myexceptions.net  网友分享于:2013-08-23  浏览:9次 <> ...

  7. 《How Tomcat Works》读书笔记(二)

    <How Tomcat Works>读书笔记(二) 这是<How Tomcat Works>第一二章的读书笔记.第一张主要写了一个静态资源处理的web服务器,第二章加了对ser ...

  8. 3D游戏设计读书笔记二

    3D游戏设计读书笔记二 一.简答题 • 解释 游戏对象(GameObjects) 和 资源(Assets)的区别与联系.   GameObjects是一个具体的实例,Assets是包括诸多游戏素材的资 ...

  9. 《Docker 技术入门与实践》-读书笔记二

    <Docker 技术入门与实践>-读书笔记一 <Docker 技术入门与实践>-读书笔记二 一.数据管理 用户在使用 Docker 的过程中,往往需要能查看容器内应用产生的数据 ...

最新文章

  1. SQLServer之创建显式事务
  2. 重载session存储方式–session_set_save_handler()
  3. base标签在ie6下的恶心问题
  4. Android常见命令
  5. python zipfile 乱码_python zipfile文件名乱码问题
  6. android奔溃日志手机查看
  7. js定时器异步请求时候 上一个请求没有响应时下一个请求已经开始_关于异步的理解...
  8. linux运行非法指令,illegal instruction非法指令的解决思路
  9. 小程序啦啦外卖、码科跑腿、云贝外卖各种问题汇总解决对策
  10. html 下拉怎么固定表头,HTML Table 固定表头简单实现
  11. 一款高颜值的词云包让我拍案叫绝
  12. android 面部识别解锁,面部识别解锁软件
  13. matlab里面sin函数是角度,matlab-如何用matlab编写sin函数要求定义一 – 手机爱问
  14. 包装类的自动装箱,自动拆箱
  15. Cannot open D:\Anaconda3\Scripts\pip-script.py 解决
  16. dede 百度主动推送插件
  17. 一个人能够哲学思考的条件
  18. Hold不住的老师 HNUST 1588
  19. 微信小程序之某荟团JS逆向
  20. kalman滤波总结

热门文章

  1. 高龄申请海外计算机科学博士,【原创】牛津在读小博谈谈在海外攻读生命科学专业的一些心得...
  2. Mybatis Plus————代码生成器
  3. LeetCode算法入门- Compare Version Numbers -day14
  4. datagridview设置为勾选才可编辑_使用lightroom前,做好这几项设置,有助于更好使用...
  5. 绿盟漏洞扫描_主机安全漏洞解决方案
  6. java摘要_java 摘要
  7. 使用Anaconda3安装pytorch、paddle环境并在pycharm里面进行环境测试
  8. python类和oop基础知识
  9. python切片原理_分析python切片原理和方法
  10. 计算机系统军训口号,霸气的军训口号大全