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

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

闭包晦涩的定义

看过很多关于闭包的定义,很多讲的云里雾里,晦涩难懂。让不少人以为闭包是多么玄乎的东西。在我看过的所有书籍中,我更喜欢《你不知道的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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/571665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

img 错误样式css,css设置图片大小_css 控制img图片的大小样式

摘要 腾兴网为您分享:css 控制img图片的大小样式&#xff0c;掌上财富&#xff0c;优品多多&#xff0c;问作业&#xff0c;淘客联盟等软件知识&#xff0c;以及手机游戏开挂神器&#xff0c;au补丁&#xff0c;局域网监测&#xff0c;苹果录屏专家&#xff0c;重复文件删除&am…

python读取视频流做人脸识别_基于 Python + OpenCV 进行人脸识别,视频追踪代码全注释...

1 #-*- coding: utf-8 -*-2 from __future__ importunicode_literals3 #操作文件4 importos5 #科学计算6 importnumpy as np7 #图像识别8 importcv2 as cv9 #数据预处理, 该项目中只使用了标签编码10 importsklearn.preprocessing as sp111213 defload_imgs(directory):14 加载…

vue css load,vue css3loadding插件的开发以及npm包的发布管理

插件开发的话建议使用vue-gitment脚手架开发vue init webpack-simple vue-gitment如果提示执行cnpm install vue-cli -g 全局安装cnpm install vue-cli -g在次执行上面的命令完成之后可以看到这样的目录在src下面添加component loadding.js loadding.vueloadding.vueexport def…

python label显示图片_python 实现在tkinter中动态显示label图片的方法

在编程中我们往往会希望能够实现这样的操作&#xff1a;点击Button&#xff0c;选择了图片&#xff0c;然后在窗口中的Label处显示选到的图片。那么这时候就需要如下代码&#xff1a;from tkinter import *from tkinter.filedialog import askopenfilenamedef choosepic():path…

如何更改服务器上的数据库文件夹,如何设置数据库文件位置

如何设置数据库文件位置08/07/2014本文内容适用于&#xff1a; Exchange Server 2007 SP3, Exchange Server 2007 SP2, Exchange Server 2007 SP1, Exchange Server 2007上一次修改主题&#xff1a; 2007-01-02本主题说明如何使用 Exchange 管理控制台或 Exchange 命令行管理程…

js删除数组中指定元素_js中数组操作详解

今天给大家带来一篇有关数组操作方法的文章。新建数组方法一&#xff1a;通过new运算符创建一个数组构造函数。var arr new Array();方法二&#xff1a;通过方括号直接创建直接量数组。var arr [1,2,3];添加数组中的元素方法一&#xff1a;通过下标添加元素。var arr new Ar…

控制台文字对战游戏 初始版

namespace 对战游戏{ class Program { #region public struct JueSe //创建一个角色对象 { public string XingMing;//这个对象中有这些属性 public int GongJi; public int ShengMing; public int…

查询链接服务器信息,如何通过 SQL Server 链接服务器和分布式查询使用 Excel

作为链接服务器查询 Excel您可以使用企业管理器、系统存储过程或 SQL-DMO(分布式管理对象)将 Excel 数据源配置为 SQL Server 链接服务器。在所有的这些情况中&#xff0c;您总需要设置以下四个属性&#xff1a;链接服务器要使用的名称。连接要使用的 OLE DB 提供程序。Excel 工…

python画精美图案_Python语言的魅力------完美图案

1.画椭圆(代码如下)#!user/bin/python# -*- conding:UTF-8 -*-if __name__ __main__:from Tkinter import *canvas Canvas(width800,height600,bgpurple)canvas.pack(expandYES,fillBOTH)k 1j 1for i in range(0,26):canvas.create_oval(310 - k,250 - k,310 k,250 k,wid…

批量下载,多文件压缩打包zip下载

0、写在前面的话图片批量下载&#xff0c;要求下载时集成为一个压缩包进行下载。从昨天下午折腾到现在&#xff0c;踩坑踩得莫名其妙&#xff0c;还是来唠唠&#xff0c;给自己留个印象的同时&#xff0c;也希望给需要用到这个方法的人带来一些帮助。1、先叨叨IO叨叨IO是因为网…

选了combobox里的选项后没激发change事件_35岁前多用利弊分析,35岁后要有“安全边际”...

想冒险&#xff0c;要趁早1/6、距离糟糕的事情发生&#xff0c;还有多远&#xff1f;我现在同时在职场和投资两类战线写文章&#xff0c;读者也开始串戏。前几天在我另外一个投资号上&#xff0c;有人问我&#xff1a;如果你把投资理念原则扩大到生活中&#xff0c;你觉得最有启…

不连续曲线 highcharts_什么是正则曲线和正则曲面

微分几何和微分流形的书上经常提到“正则曲线”和“正则曲面”。其实英文书中写作”Regular Curve“和”Regular Surface“&#xff0c;让人一眼能够了解其大意&#xff08;这也是我更偏向看英文原版书的原因&#xff09;。我就想&#xff0c;数学家为啥不翻译成”规则曲线“和…

centos安装 node.js

curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash - yum clean all yum makecache yum -y install nodejs转载于:https://www.cnblogs.com/linkenpark/p/7810238.html

11.06

{% extendsdaohang.html %} {% block title %}发布问答{% endblock %} {% block head %}<link rel"stylesheet" href"{{ url_for(static,filenamecss/14.css) }}" type"text/css"> {% endblock %}{% block main %}<div class"box&…

python 安卓模拟器电脑版_【夜神安卓模拟器电脑版】夜神安卓模拟器电脑版 V6.6.0.6免费版官方免费下载_正式版下载-多特软件站...

夜神安卓模拟器是目前非常流行的一款安卓模拟器&#xff0c;相比一般的模拟器它具有更好的兼容性&#xff0c;稳定性&#xff0c;系统基于Android4.4.2&#xff0c;可以更好地兼容安卓软件&#xff0c;安卓游戏&#xff0c;可以放心使用&#xff0c;软件使用非常简单。相关软件…

python爬取10个网站_十个Python爬虫武器库示例,十个爬虫框架,十种实现爬虫的方法!...

一般比价小型的爬虫需求&#xff0c;我是直接使用requests库 bs4就解决了&#xff0c;再麻烦点就使用selenium解决js的异步 加载问题。相对比较大型的需求才使用框架&#xff0c;主要是便于管理以及扩展等。1.ScrapyScrapy是一个为了爬取网站数据&#xff0c;提取结构性数据而…

[W班]第二次结对作业成绩评价

作业地址&#xff1a; https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1715W/homework/1016 作业要求&#xff1a; 1、代码具有规范性。 2、实现的程序语言不做限制性要求&#xff0c;但需要能生成Windows平台的可执行文件。C/C/C#编译后即可生成&#xff0c;其他…

resnet50结构_无需额外数据、Tricks、架构调整,CMU开源首个将ResNet50精度提升至80%+新方法

本文是CMU的Zhiqiang Shen提出的一种提升标准ResNet50精度的方法&#xff0c;它应该是首个将ResNet50的Top1精度刷到80%的(无需额外数据&#xff0c;无需其他tricks&#xff0c;无需网络架构调整)。该文对于研究知识蒸馏的同学应该是有不少可参考的价值&#xff0c;尤其是里面提…

msp430项目编程14

msp430中项目---电子测重系统 1、hx711工作原理 2、电路原理说明 3、代码&#xff08;显示部分&#xff09; 4、代码&#xff08;功能实现&#xff09; 5、项目总结 msp430项目编程msp430入门学习转载于:https://www.cnblogs.com/guochaoxxl/p/7818040.html

linq to sql 行转列_SQL 难题:行转列

问题&#xff1a;有一张学生成绩表sc&#xff08;sid 学号&#xff0c;cid 课程&#xff0c;score 成绩&#xff09;&#xff0c;请查询出每个学生的英语、数学的成绩&#xff08;行转列&#xff0c;一个学生只有一行记录&#xff09;。建表语句&#xff1a;create 实现方式1—…