【转】深入浅出JavaScript之闭包(Closure)
闭包(closure)是掌握Javascript从人门到深入一个非常重要的门槛,它是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。下面写下我的学习笔记~
闭包-无处不在
在前端编程中,使用闭包是非常常见的,我们经常有意无意,直接或间接用到了闭包。闭包可以使传递数据更加灵活(比如处理一些点击事件)
|
1
2
3
4
5
6
7
|
!function() { var localData = "localData here"; document.addEventListener('click', //处理点击事件时用到了外部局部变量,比如这里的localData function(){ console.log(localData); }); }(); |
又比如下面这个例子:(是不是很亲切~~)
|
1
2
3
4
5
6
7
8
9
10
11
|
!function() { var localData = "localData here"; $.ajax({ url : url, success : function() { // do sth... console.log(localData); } }); }(); |
再来看一个例子~~这种情况就是我们通常所说的闭包
|
1
2
3
4
5
6
7
8
|
function outer() { var localVal = 30; return function(){ return localVal; } } var func = outer(); func(); // 30 |
这个例子中调用outer()返回匿名函数function(),这个匿名函数中可以访问outer()的局部变量localVal,在outer()调用结束后,再次调用func()的时候,仍然能访问到outer()的局部变量localVal
闭包的概念
闭包,不同于一般的函数,它允许一个函数在立即词法作用域外调用时,仍可访问非本地变量。 --维基百科
闭包就是能够读取其他函数内部变量的函数。 --阮一峰
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁
闭包的用途
这部分转自这篇博文
闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
(function() { var _userId = 23492; var _typeId = 'item'; var export = {}; function converter(userId) { return +userId; } export.getUserId = function() { return converter(_userId); } export.getTypeId = function() { return _typeId; } window.export = export; //通过此方式输出}()); export.getUserId(); // 23492 export.getTypeId(); // item export._userId; // undefined export._typeId; // undefined export.converter; // undefined |
利用闭包的特性能让我们封装一些复杂的函数逻辑,在这个例子中调用export上的方法(getUserId,getTypeId)间接访问函数里私有变量,但是直接调用export._userId是没法拿到_userId的。这也是Node里面常用到特性吧~
常见错误之循环闭包
下面这个案例,我们添加3个div,值分别为aaa,bbb,ccc,我们想实现的是点击aaa输出1,点击bbb输出2,点击ccc输出3
|
1
2
3
4
5
6
7
|
document.body.innerHTML = "<div id=div1>aaa</div>" + "<div id=div2>bbb</div><div id=div3>ccc</div>"; for (var i = 1; i < 4; i++) { document.getElementById('div' + i). addEventListener('click', function() { alert(i); // all are 4! }); } |

结果点击aaa,bbb还是ccc都是alert(4)~~
产生这样的问题在于这个i的值在初始化完成的时候就已经是4了
要达到我们想要的点击aaa输出1,点击bbb输出2,点击ccc输出3,要用到闭包的技巧,在每次循环的时候,用立即执行的匿名函数把它包装起来,这样子做的话,每次alert(i)的值就取自闭包环境中的i,这个i来自每次循环的赋值i就能输出1,2,3了
|
1
2
3
4
5
6
7
8
9
|
document.body.innerHTML = "<div id=div1>aaa</div>" + "<div id=div2>bbb</div>" + "<div id=div3>ccc</div>"; for (var i = 1; i < 4; i++) { !function(i){ //②再用这个参数i,到getElementById()中引用 document.getElementById('div' + i). addEventListener('click', function() { alert(i); // 1,2,3 }); }(i); //①把遍历的1,2,3的值传到匿名函数里面} |

思考题
如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。(来自阮老师)这题目总结得真妙~~
代码片段一。
|
1
2
3
4
5
6
7
8
9
10
|
var name = "The Window";var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; }};alert(object.getNameFunc()()); |
代码片段二。
|
1
2
3
4
5
6
7
8
9
10
11
|
var name = "The Window";var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; }};alert(object.getNameFunc()()); |
【转】深入浅出JavaScript之闭包(Closure)的更多相关文章
- JavaScript 的闭包(closure)
以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/ 对于闭包的理解,其实可以归纳为,在创建函数时,同时创建了一 ...
- 深入浅出JavaScript之闭包(Closure)
闭包(closure)是掌握Javascript从人门到深入一个非常重要的门槛,它是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.下面写下我的学习笔记~ 闭包-无处不 ...
- javaScript深入浅出之理解闭包
javaScript深入浅出之理解闭包 引言 闭包是个老生长谈的话题了,对于闭包网上也有很多不同的看法 <你不知道的javaScript>对于闭包是这么定义的:函数创建和函数执行不在同一个 ...
- JavaScript闭包(Closure)
JavaScript闭包(Closure) 本文收集了多本书里对JavaScript闭包(Closure)的解释,或许会对理解闭包有一定帮助. <你不知道的JavsScript> Java ...
- 深入理解JavaScript闭包(closure)
最近在网上查阅了不少javascript闭包(closure)相关的资料,写的大多是非常的学术和专业.对于初学者来说别说理解闭包了,就连文字叙述都很难看懂.撰写此文的目的就是用最通俗的文字揭开Java ...
- [转载]学习Javascript闭包(Closure)
学习Javascript闭包(Closure) 源地址: http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures ...
- 在Javascript中闭包(Closure)
在Javascript中闭包(Closure) 什么是闭包 “官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. ...
- javascript 闭包(closure)
<script type="text/javascript"> //闭包(closure):内层函数可以引用存在于包围它的函数内的变量,即使外层函数的执行已经结束 ...
- javascript中的闭包closure详解
目录 简介 函数中的函数 Closure闭包 使用闭包实现private方法 闭包的Scope Chain 闭包常见的问题 闭包性能的问题 总结 简介 闭包closure是javascript中一个非 ...
随机推荐
- 如何选择靠谱的app外包公司,2017最新资讯
企业在外包开发app之前最纠结的问题就是如何选择一个靠谱的app外包公司.因为一个靠谱的app外包公司非常重要,完全决定了app外包开发的周期.bug.售后服务等各方面问题,可以说app开发外包团队一 ...
- Android开发之Android Material Design Toolbar自定义随笔
一.自定义Toolbar的menu: 在menu下新建menu.xml文件,自定义menu的样式: <menu xmlns:android="http://schemas.androi ...
- JavaScript高级编程 (2) - HTML 与 JavaScript
向HTML 页面中插入JavaScript 的主要方法,就是使用<script>元素.这个元素由Netscape 创造并在Netscape Navigator 2 中首先实现.后来,这个元 ...
- 【原创】记一次Project插件开发
一.开发背景 最近在使用微软的Office Project 2010 进行项目管理,看到排的满满的计划任务,一个个地被执行完毕,还是很有成就感的.其实,不光是在工作中可以使用Project进行项目进度 ...
- blocking and unblocking mechanism for linux drivern code
概念: 1> 阻塞操作 是指在执行设备操作时,若不能获得资源,则挂起进程直到满足操作条件后再进行操作.被挂起的进程进入休眠,被从调度器移走,直到条件满足: 2> 非阻塞操作 在 ...
- Hibernate(1)——数据访问层的架构模式
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 数据库的概念.逻辑.数据模型概念 应用程序的分层体系结构发展 MVC设计模式与四层结构的对应关系 持久层的设 ...
- NodeJs对Mysql封装
之前在学习NodeJs的时候,每次操作数据库都需要连接数据库然后开始写Sql操作,这样非常麻烦,然后自己对Mysql进行了封装,一共100多行代码. github地址: Mysql操作 我在里面对My ...
- 父页面操作iframe子页面的安全漏洞及跨域限制问题
一.父子交互的跨域限制 同域情况下,父页面和子页面可以通过iframe.contentDocument或者parent.document来交互(彼此做DOM操作等,如父页面往子页面注入css). 跨域 ...
- 安卓第一次启动引导页使用ViewPager实现
我们在安装某个APP的时候,基本都会有一个引导页的提示,他们可以打广告,或者介绍新功能的加入和使用说明等.一般都支持滑动并且下面有几个点,显示共有多少页和当前图片的位置,在IOS上这个实现起来比较简单 ...
- Sass学习笔记之入门篇
Sass又名SCSS,是CSS预处理器之一,,它能用来清晰地.结构化地描述文件样式,有着比普通 CSS 更加强大的功能. Sass 能够提供更简洁.更优雅的语法,同时提供多种功能来创建可维护和管理的样 ...