JavaScript 闭包(Closure)
闭包(closure)是掌握Javascript从人门到深入一个非常重要的门槛,它是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。
闭包-无处不在
在前端编程中,使用闭包是非常常见的,我们经常有意无意,直接或间接用到了闭包。闭包可以使传递数据更加灵活(比如处理一些点击事件)
!function() {
var localData = "localData here";
document.addEventListener('click', //处理点击事件时用到了外部局部变量,比如这里的localData
function(){
console.log(localData);
});
}();
又比如下面这个例子:(是不是很亲切~~)
!function() {
var localData = "localData here";
var url = "http://www.baidu.com/";
$.ajax({
url : url,
success : function() {
// do sth...
console.log(localData);
}
});
}();
再来看一个例子~~这种情况就是我们通常所说的闭包
function outer() {
var localVal = 30;
return function(){
return localVal;
}
}
var func = outer();
func(); // 30
这个例子中调用outer()返回匿名函数function(),这个匿名函数中可以访问outer()的局部变量localVal,在outer()调用结束后,再次调用func()的时候,仍然能访问到outer()的局部变量localVal
闭包的概念
闭包,不同于一般的函数,它允许一个函数在立即词法作用域外调用时,仍可访问非本地变量。 --维基百科
闭包就是能够读取其他函数内部变量的函数。 --阮一峰
由于在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,可以在函数外部对函数内部的局部变量进行操作。
闭包-封装
(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
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了
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的值传到匿名函数里面
}
思考题
如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。(来自阮老师)这题目总结得真秒~~
代码片段一。
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()());
JavaScript 闭包(Closure)的更多相关文章
- 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)
<script type="text/javascript"> //闭包(closure):内层函数可以引用存在于包围它的函数内的变量,即使外层函数的执行已经结束 ...
- JavaScript闭包(closure)入门: 拿"开发部"和"技术牛"举个例子
虽然只是一小段菜鸟的学习笔记 , 不过还是希望看到的高手看到不足的时候帮忙指点~ 一:代码和执行过程 /** * http://blog.csdn.net/ruantao1989 * ==>Ju ...
- JavaScript闭包(二)——作用
一.延迟调用 当在一段代码中使用 setTimeout 时,要将一个函数的引用作为它的第一个参数,而将以毫秒表示的时间值作为第二个参数. 但是,传递函数引用的同时无法为计划执行的函数提供参数.可以在代 ...
- JavaScript闭包(一)——实现
闭包的官方的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 通俗点的说法是: 从理论角度:所有的函数.因为它们都在创建的时候就将上层上下文 ...
- JavaScript闭包——实现
闭包的官方的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 通俗点的说法是: 从理论角度:所有的函数.因为它们都在创建的时候就将上层上下文 ...
- JavaScript学习总结(十六)——Javascript闭包(Closure)
原文地址: http://www.cnblogs.com/xdp-gacl/p/3703876.html 闭包(closure)是Javascript语言的一个难点,也是它的特色, 很多高级应用都要依 ...
- javascript中的闭包closure详解
目录 简介 函数中的函数 Closure闭包 使用闭包实现private方法 闭包的Scope Chain 闭包常见的问题 闭包性能的问题 总结 简介 闭包closure是javascript中一个非 ...
随机推荐
- 机器学习——大数据与MapReduce
MapReduce是一个分布式计算框架 优点:可在短时间内完成大量工作 缺点:算法必须经过重写,需要对系统工程有一定的理解 使用数据类型:数值型和标称型数据 MapReduce在大量节点组成的集群上运 ...
- OpenGL核心技术之帧缓冲
笔者介绍:姜雪伟.IT公司技术合伙人,IT高级讲师.CSDN社区专家.特邀编辑.畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...
- ColorSense颜色检测器
下载地址:https://github.com/omz/ColorSense-for-Xcode 修改OMColorSense.xcodeproj工程里的OMColorHelper.m文件的内容,实现 ...
- [转]Python多线程与多线程中join()的用法
https://www.cnblogs.com/cnkai/p/7504980.html Python多线程与多进程中join()方法的效果是相同的. 下面仅以多线程为例: 首先需要明确几个概念: 知 ...
- Unity判断网络是否连接以及判断是否连接WiFi
由于项目中的核心模块需要用到网络连接,所以需要首先检测用户是否有网络百度了下,有人说通过连接自己的服务器进行测试的,也有人说通过延迟来判断的最后发现原来Unity是提供了网络判断的方法的.Networ ...
- BareTail大文件日志实时查看工具
BareTail 动态的查看日志文件,就像Linux上的tail tail -f nohup.out 功能: 实时文件查看 tail命令模式,自动滚动 支持2g以上大文件 自动滚动 彩色监控 多文件监 ...
- [转]好文章:Android的AlertDialog详解
refer:http://www.2cto.com/kf/201205/131876.html AlertDialog的构造方法全部是Protected的,所以不能直接通过new一个AlertDial ...
- PHP 数组current和next用法
1.current 当前数组 <?php $transport = array('foot', 'bike', 'car', 'plane'); $mode = current($trans ...
- centos下快速安装JDK
Linux系统自带了jdk(当然,如果没有,可以忽略这个步骤),但还是1.4的老版本,所以需要先卸载,然后在安装1.6,卸载步骤如下: [root@localhost ~]# rpm -qa | gr ...
- ios开发之--数组的一些操作
1,创建数组 NSMutableArray * array =[[NSMutableArray alloc] initWithObjects:@"a",@"b" ...