当前位置: 首页 > 编程日记 > 正文

关于JavaScript的闭包(closure)

(转载自阮一峰博客)

包(closure)是Javascript语言的一个难点,也是它的特色,更是函数式编程的重要思想之一,很多高级应用都要依靠闭包实现。

下面就是我的学习笔记,对于Javascript初学者应该是很有用的。

一、变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

var n=999;

function f1(){     alert(n);   }

f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

function f1(){     var n=999;   }

alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

function f1(){     n=999;   }

f1();

alert(n); // 999

二、如何从外部读取局部变量?

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

那就是在函数的内部,再定义一个函数。

function f1(){

var n=999;

function f2(){       alert(n); // 999     }

}

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

function f1(){

var n=999;

function f2(){       alert(n);     }

return f2;

}

var result=f1();

result(); // 999

三、闭包的概念

上一节代码中的f2函数,就是闭包。

各种专业文献上的"闭包"(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

四、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

怎么来理解这句话呢?请看下面的代码。

function f1(){

var n=999;

nAdd=function(){n+=1}

function f2(){       alert(n);     }

return f2;

}

var result=f1();

result(); // 999

nAdd();

result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

六、思考题

如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。

代码片段一。

var name = "The Window";

var object = {

name : "My Object",

getNameFunc : function(){

return function(){

return this.name;

};

}

};

alert(object.getNameFunc()());

代码片段二。

var name = "The Window";

var object = {

name : "My Object",

getNameFunc : function(){

var that = this;

return function(){

return that.name;

};

}

};

alert(object.getNameFunc()());

七、思考题答案

文章源出处并未对上述代码进行解释,本人不才,凭自己的理解,对上述代码执行结果做出解释,若有不正之处,还望大家不吝赐教。

上述的代码,运行结果,第一个为"The Window",第二个为"My Object"。对象定义的getNameFunc函数返回的是一个闭包,即一个匿名函数,其返回值为this.name;当在第一个调用的时候,闭包(即getNameFunc函数中的匿名函数)获到的this对象并未在外部进行重新绑定,因此该this对象不是Object,而是更外一层所定义的this,即window,因此返回的name值为外部空间的name值。第二个函数使用that对this(此时的this即为object对象本身)进行了局部变量绑定,这时,闭包捕获到的即为that,也即object对象本身,故此时返回的name值为object对象中的值。

转载于:https://www.cnblogs.com/ciangcic/p/3625499.html

相关文章:

Vagrant控制管理器——“Hobo”

Hobo是控制Vagrant盒子和在Mac上编辑Vagrantfiles的最佳和最简单的方法。您可以快速启动,停止和重新加载您的Vagrant机器。您可以从头开始轻松创建新的Vagrantfile。点击进入,尽享Hobo for Mac全部功能! Hobo做什么? 启动&#xf…

微众银行AI团队开源联邦学习框架,并发布《联邦学习白皮书1.0》

(图片由AI科技大本营付费下载自视觉中国)编辑 | Jane来源 | 《联邦学习白皮书1.0》出品 | AI科技大本营(ID:rgznai100)【导语】2019年,联邦学习成为业界技术研究与应用的焦点。近日,微众银行 AI 项目组编制…

C++11中头文件atomic的使用

原子库为细粒度的原子操作提供组件,允许无锁并发编程。涉及同一对象的每个原子操作,相对于任何其他原子操作是不可分的。原子对象不具有数据竞争(data race)。原子类型对象的主要特点就是从不同线程访问不会导致数据竞争。因此从不同线程访问某个原子对象…

Oracle回收站

回收站是删除对象使用的存储空间。可以使用实例参数recyclebin禁用回收站,默认是on,可以为某个会话或系统设置为off或on。所有模式都有一个回收站。 当表空间不足时可以自动重用回收站对象占用的表空间(此后不可能恢复对象)&#…

协方差矩阵介绍及C++/OpenCV/Eigen的三种实现

函数f(x)关于某分布P(x)的期望(expectation)或者期望值(expected value)是指,当x由P产生,f作用于x时,f(x)的平均值。对于离散型随机变量,这可以通过求和得到:对于连续型随机变量可以通过求积分得到:当概率分…

10分钟搭建你的第一个图像识别模型 | 附完整代码

(图片由AI科技大本营付费下载自视觉中国)作者 | Pulkit Sharma译者 | 王威力来源 | 数据派THU(ID:DatapiTHU)【导读】本文介绍了图像识别的深度学习模型的建立过程,通过陈述实际比赛的问题、介绍模型框架和…

Rancher 2.2.2 发布,优化 Kubernetes 集群运维

开发四年只会写业务代码,分布式高并发都不会还做程序员? >>> Rancher 2.2.2 发布了。Rancher 是一个开源的企业级 Kubernetes 平台,可以管理所有云上、所有发行版、所有 Kubernetes集群,解决了生产环境中企业用户可能面…

EXP/EXPDP, IMP/IMPDP应用

2019独角兽企业重金招聘Python工程师标准>>> EXP/EXPDP, IMP/IMPDP应用 exp name/pwddbname filefilename.dmp tablestablename rowsy indexesn triggersn grantsn $ sqlplus username/passwordhostname:port/SERVICENAME OR $ sqlplus username Enter password:…

微软语音AI技术与微软听听文档小程序实践 | AI ProCon 2019

演讲嘉宾 | 赵晟、张鹏整理 | 伍杏玲来源 | CSDN(ID:CSDNnews)【导语】9 月 7 日,在CSDN主办的「AI ProCon 2019」上,微软(亚洲)互联网工程院人工智能语音团队首席研发总监赵晟、微软&#xff0…

C++11中std::condition_variable的使用

<condition_variable>是C标准程序库中的一个头文件&#xff0c;定义了C11标准中的一些用于并发编程时表示条件变量的类与方法等。条件变量是并发程序设计中的一种控制结构。多个线程访问一个共享资源(或称临界区)时&#xff0c;不但需要用互斥锁实现独享访问以避免并发错…

docker基础文档(链接,下载,安装)

一、docker相关链接1.docker中国区官网(包含部分中文文档&#xff0c;下载安装包&#xff0c;镜像加速器)&#xff1a;https://www.docker-cn.com/2.docker官方镜像仓库&#xff1a;https://cloud.docker.com/3.docker下载&#xff1a;https://www.docker-cn.com/community-edi…

一个JS对话框,可以显示其它页面,

还不能自适应大小 garyBox.js // JavaScript Document// gary 2014-3-27// 加了 px 在google浏览器没加这个发现设置width 和height没有用 //gary 2014-3-27 //实在不会用那些JS框架&#xff0c;自己弄个&#xff0c;我只是想要个可以加载其它页面的对话框而以,这里用了别人的…

只需4秒,这个算法就能鉴别你的LV是真是假

&#xff08;图片付费下载自视觉中国&#xff09;导语&#xff1a;假冒奢侈品制造这个屡禁不止的灰色产业&#xff0c;每年给正品商家和消费者造成上千亿的损失&#xff0c;对企业和消费者造成伤害。作为全球奢侈品巨头&#xff0c;LVMH 对假冒奢侈品的打击十分重视。LVMH 其旗…

概率论中伯努利分布(bernoulli distribution)介绍及C++11中std::bernoulli_distribution的使用

Bernoulli分布(Bernoulli distribution)&#xff1a;是单个二值随机变量的分布。它由单个参数∈[0,1]&#xff0c;给出了随机变量等于1的概率。它具有如下的一些性质&#xff1a;P(x1) P(x0)1-P(xx) x(1-)1-xEx[x] Varx(x) (1-)伯努力分布(Bernoulli distribution&#xff0c;又…

关于View测量中的onMeasure函数

在自定义View中我们通常会重写onMeasure&#xff0c;下面来说说这个onMeasure有什么作用 onMeasure主要用于对于View绘制时进行测量 Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);…

zabbix二次开发之从mysql取值在运维平台js图表展现

前沿&#xff1a;集群控制平台已经要慢慢的灰度上线了&#xff0c;出问题的时候&#xff0c;才找点bug&#xff0c;时间有点空闲。正好看了下zabbix的数据库&#xff0c;产生了自己想做一套能更好的展现zabbix的页面。更多内容请到我的个人的博客站点&#xff0c;blog.xiaorui.…

概率论中高斯分布(正态分布)介绍及C++11中std::normal_distribution的使用

高斯分布&#xff1a;最常用的分布是正态分布(normal distribution)&#xff0c;也称为高斯分布(Gaussian distribution)&#xff1a;正态分布N(x;μ,σ2)呈现经典的”钟形曲线”的形状&#xff0c;其中中心峰的x坐标由μ给出&#xff0c;峰的宽度受σ控制。正态分布由两个参数…

AI落地遭“卡脖子”困境:为什么说联邦学习是解决良方?

作者 | Just出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;毋庸置疑&#xff0c;在业界对人工智能&#xff08;AI&#xff09;应用落地备受期待的时期&#xff0c;数据这一重要支点却越来越成为一个“卡脖子”的难题。AI落地需要数据来优化模型效果&#xff0c;但大…

Linux下截取指定时间段日志并输出到指定文件

sed -n /2019-04-22 16:10:/,/2019-04-22 16:20:/p log.log > bbb.txt 转载于:https://www.cnblogs.com/mrwuzs/p/10752037.html

nginx+keepalive主从双机热备+自动切换解决方案

环境采集cenots 6.3 64位迷你安装&#xff0c;因为安装前&#xff0c;你需要做一些工作yum install -y make wget如果你愿意可以更新下系统&#xff0c;更换下yum源.1.安装keepalive官方最新版 keepalived-1.2.7tar zxvf keepalived-1.2.7.tar.gzcd keepalived-1.2.7在此之前。…

概率论中指数分布介绍及C++11中std::exponential_distribution的使用

指数分布&#xff1a;在深度学习中&#xff0c;我们经常会需要一个在x0点处取得边界点(sharp point)的分布。为了实现这一目的&#xff0c;我们可以使用指数分布(exponential distribution)&#xff1a; p(x;λ) λlx≥0exp(-λx)指数分布使用指示函数(indicator function) lx≥…

肖仰华:知识图谱构建的三要素、三原则和九大策略 | AI ProCon 2019

演讲嘉宾 | 肖仰华&#xff08;复旦大学教授、博士生导师&#xff0c;知识工场实验室负责人&#xff09; 编辑 | Jane 出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 近两年&#xff0c;知识图谱技术得到了各行各业的关注&#xff0c;无论是企业公司还…

Docker mongo副本集环境搭建

1、MongoDB Docker 镜像安装 docker pull mongo 2、Docker容器创建 MongoDB Docker 容器创建有以下几个问题&#xff1a; 1- MongoDB 容器基本创建方法和数据目录挂载 2- MongoDB 容器的数据迁移 3- MongoDB 设置登录权限问题docker run -p 27017:27017 -v <LocalDirectoryP…

菜鸟学习HTML5+CSS3(一)

主要内容&#xff1a; 1.新的文档类型声明&#xff08;DTD&#xff09; 2.新增的HTML5标签 3.删除的HTML标签 4.重新定义的HTML标签 一、新的文档类型声明&#xff08;DTD&#xff09; HTML 5的DTD声明为&#xff1a;<!doctype html>、<!DOCTYPE html>、<!DOCTY…

激活函数之logistic sigmoid函数介绍及C++实现

logistic sigmoid函数&#xff1a;logistic sigmoid函数通常用来产生Bernoulli分布中的参数&#xff0c;因为它的范围是(0,1)&#xff0c;处在的有效取值范围内。logisitic sigmoid函数在变量取绝对值非常大的正值或负值时会出现饱和(saturate)现象&#xff0c;意味着函数会变得…

NLP重要模型详解,换个方式学(内附资源)

&#xff08;图片有AI科技大本营付费下载自视觉中国&#xff09;作者 | Jaime Zornoza&#xff0c;马德里技术大学译者 | 陈之炎校对 | 王威力编辑 | 黄继彦来源 | 数据派THU&#xff08;ID&#xff1a;DatapiTHU&#xff09;【导语】本文带你以前所未有的方式了解深度学习神经…

大闸蟹的OO第二单元总结

OO的第二单元是讲多线程的协作与控制&#xff0c;三次作业分别为FAFS电梯&#xff0c;ALS电梯和三部需要协作的电梯。三次作业由浅入深&#xff0c;让我们逐渐理解多线程的工作原理和运行状况。 第一次作业&#xff1a; 第一次作业是傻瓜电梯&#xff0c;也就是完全不需要考虑捎…

构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(31)-MVC使用RDL报表

原文:构建ASP.NET MVC4EF5EasyUIUnity2.x注入的后台管理系统&#xff08;31&#xff09;-MVC使用RDL报表这次我们来演示MVC3怎么显示RDL报表,坑爹的微软把MVC升级到5都木有良好的支持报表,让MVC在某些领域趋于短板 我们只能通过一些方式来使用rdl报表。 Razor视图不支持asp.net…

18段代码带你玩转18个机器学习必备交互工具

&#xff08;图片有AI科技大本营付费下载自视觉中国&#xff09;作者 | 曼纽尔阿米纳特吉&#xff08;Manuel Amunategui&#xff09;、迈赫迪洛佩伊&#xff08;Mehdi Roopaei&#xff09;来源 | 大数据&#xff08;ID&#xff1a;hzdashuju&#xff09;【导读】本文简要介绍将…

激活函数之ReLU/softplus介绍及C++实现

softplus函数(softplus function)&#xff1a;ζ(x)ln(1exp(x)).softplus函数可以用来产生正态分布的β和σ参数&#xff0c;因为它的范围是(0,∞)。当处理包含sigmoid函数的表达式时它也经常出现。softplus函数名字来源于它是另外一个函数的平滑(或”软化”)形式&#xff0c;这…