javascript闭包(Closure)初探

转载 2015年11月19日 16:39:27

closure被翻译成“闭包”,感觉这东西被包装的太学术化。下面参考书本和网上资源简单探讨一下(理解不当之处务请留意)。
1、什么是闭包
官方的回答:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
看了上面的定义,如果你不是高手,我坚信你会和我一样愤怒的质问:这tmd是人话吗?
要理解闭包,还是代码最有说服力啊,上代码:


function funcTest()
{
  
var tmpNum=100//私有变量

  
//在函数funcTest内定义另外的函数作为funcTest的方法函数
  function innerFuncTest(
  {
       alert(tmpNum); 
//引用外层函数funcTest的临时变量tmpNum
  }

  
return innerFuncTest; //返回内部函数
}

//调用函数
var myFuncTest=funcTest(); 
myFuncTest();
//弹出100

上面代码中,注释已经写的清清楚楚。现在我们可以这么理解“闭包”:在函数体内定义另外的函数作为目标对象的方法函数(示例中就是在函数funcTest内定义另外的函数innerFuncTest作为funcTest的方法函数),而这个对象的方法函数反过来引用外层函数体中的临时变量(闭包是一种间接保持变量值的机制。示例中就是内部函数innerFuncTest引用外层函数funcTest的临时变量tmpNum,这里必须注意,临时变量可以包括外部函数中声明的所有局部变量参数和声明的其他内部函数)。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包(示例中,调用函数的时候,myFuncTest实际调用的是innerFuncTest函数,也就是说funcTest的一个内部函数innerFuncTest在funcTest之外被调用,这时就创建了一个闭包)。
2、两个利用闭包的例子
下面举两个例子,一个是因为闭包导致了问题,而另一个则利用闭包巧妙地通过函数的作用域绑定参数。
这两个例子相关的HTML标记片断如下:
<a href="#" id="closureTest0">利用闭包的例子(1秒后会看到提示)</a><br />
<a href="#" id="closureTest1">由于闭包导致问题的例子1</a><br />
<a href="#" id="closureTest2">由于闭包导致问题的例子2</a><br />
<a href="#" id="closureTest3">由于闭包导致问题的例子3</a><br />
(1)、因闭包而导致问题
上面的HTML标记片断中有4个<a>元素,现在要给后三个指定事件处理程序,使它们在用户单击时报告自己在页面中的顺序,比如:当用户单击第2个链接时,报告“您单击的是第1个链接”。为此,如果编写下列为后三个链接添加事件处理程序的函数:

Code

然后,在页面载入完成后(不然可能会报错)调用该函数:
window.onload = function(){
    badClosureExample();
}
看一下运行结果,此时单击后3个链接,会看到警告框中显示什么信息呢?——全都是“您单击的是第4个链接”。是不是令你感到十分意外?为什么?
分析:因为在badClosureExample()函数中指定给element.onclick的事件处理程序,也就是onclick那个匿名函数是在badClosureExample()函数运行完成后(用户单击链接时)才被调用的。而调用时,需要对变量i求值,解析程序首先会在事件处理程序内部查找,但i没有定义。然后,又到 badClosureExample()函数中查找,此时有定义,但i的值是4(只有i大于4才会停止执行for循环)。因此,就会取得该值——这正是闭包(匿名函数)要使用其外部函(badClosureExample)作用域中变量的结果。而且,这也是由于匿名函数本身无法传递参数(故而无法维护自己的作用域)造成的。
那么这个例子的问题怎么解决呢?其实方法有很多(自己不妨写一下看看),我认为比较简单直接的代码:

Code

(2)、巧妙利用闭包绑定参数
 还是上面的HTML片段,我们要在用户单击第一个链接时延时弹出一个警告框,怎么实现?答案是使用setTimeout()函数,这个函数会在指定的毫秒数之后调用一个函数,如:
setTimeout(someFunc,1000);
但问题是,无法给其中的someFunc函数传递参数。而使用闭包则可以轻松解决这个问题:

function goodClosureExample(oMsg){
    
return function(){
        alert(oMsg);
    };
}

函数goodClosureExample用来返回一个匿名函数(闭包)。而我们可以通过为它传递参数来使返回的匿名函数绑定该参数,如:
var good = goodClosureExample('这个参数是通过闭包绑定的');
而此时,就可以将绑定了参数的good函数传递给setTimeout()实现延时警告了:
setTimeout(good,1000) //此时good中已经绑定了参数
最后,测试通过的完整代码:

Code

3、javascript的垃圾回收原理
(1)、在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收;
(2)、如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。
在js中使用闭包,往往会给javascript的垃圾回收器制造难题。尤其是遇到对象间复杂的循环引用时,垃圾回收的判断逻辑非常复杂,搞不好就有内存泄漏的危险,所以,慎用闭包。ms貌似已经不建议使用闭包了。

Java中的闭包(Closure)和回调

上网看了许多关于Java中的闭包(Closure)和回调的博文,总算是弄清晰了,再次写下自己的笔记   1、闭包 定义:闭包允许你将一些行为封装,将它像一个对象一样传来递去,而且它依然能够访问 到原来...
  • woailuo453786790
  • woailuo453786790
  • 2016年06月07日 22:09
  • 2002

Swift 闭包(Closure)回调传值

实现例子由两个界面组成 A - > B 使用属性传值 B - > A 使用闭包进行反向回调传值Swift 使用闭包(Closure)传值的原理,与OC 中使用代码块(block)传值原理,基本类似...
  • ljh910329
  • ljh910329
  • 2015年08月11日 16:55
  • 5523

PHP闭包(Closure)

匿名函数 提到闭包就不得不想起匿名函数,也叫闭包函数(closures),貌似PHP闭包实现主要就是靠它。声明一个匿名函数是这样: $func = function() { }; //带结束...
  • jinbiao520
  • jinbiao520
  • 2013年06月23日 17:16
  • 2106

PHP闭包(Closure)初探_豆浆油条

PHP闭包(Closure)初探 2013-05-01 23:42 by 豆浆油条 - melon, 6763 阅读, 4 评论, 收藏, 编辑 不知不觉发现PHP已经出到了5.5版本,而...
  • lhorse003
  • lhorse003
  • 2017年05月19日 21:06
  • 183

学习Javascript闭包(Closure)

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。下面就是我的学习笔记,对于Javascript初学者应该是很有用的。 一、变量的作用域     ...
  • y4786924
  • y4786924
  • 2013年08月12日 22:18
  • 291

学习Javascript闭包(Closure)

作者: 阮一峰 文章出处:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html 闭包(closure...
  • zsr1860
  • zsr1860
  • 2017年12月25日 13:40
  • 22

Javascript中闭包(closure)的理解与浅析

最近在网上查阅了不少Javascript闭包(closure)相关的资料,写的大多是非常的学术和专业。对于初学者来说别说理解闭包了,就连文字叙述都很难看懂。撰写此文的目的就是用最通俗的文字揭开Java...
  • xingchengzh
  • xingchengzh
  • 2012年01月04日 22:43
  • 165

学习Javascript闭包(Closure)

在javascript中,子函数可以读取父函数中的变量,而父函数却无法读取子函数中的变量,就像是儿子可以花父亲的钱,而父亲却不能花儿子的钱。而闭包要做的就是把儿子的钱拿出来给父亲花。 闭包通过在...
  • sir1241
  • sir1241
  • 2016年10月11日 17:18
  • 121

Javascript闭包(Closure)代码详解

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。很早就接触过闭包这个概念了,但是一直糊里糊涂的,没有能够弄明白JavaScript的闭包到底是什...
  • HUXU981598436
  • HUXU981598436
  • 2016年06月11日 16:42
  • 237

学习 JavaScript 最难点之二 -- 理解closure(闭包)

在理解闭包之前, 首先要清楚JS中的作用域只有2种: 全局作用域和方法作用域 全局作用域很好理解了, 方法作用域就是指一个 function 形成一个独立的作用域, 而且方法作用域还能够嵌套.与别的...
  • mimixiao345
  • mimixiao345
  • 2015年07月27日 22:20
  • 256
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:javascript闭包(Closure)初探
举报原因:
原因补充:

(最多只允许输入30个字)