闭包

转载 2018年04月16日 14:46:26

一、闭包的概念:

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

二、闭包的特性:

1.函数内再嵌套函数

2.内部函数可以引用外层的参数和变量

3.参数和变量不会被垃圾回收机制回收

搞不明白闭包的,十之八九都不会C语言,估计java也不会,否则不会这么纠结于这个概念。在java中,引用类型变量只要存在引用,就不会被销毁,引用本身也是个变量,是值传递,因此,可以通过函数返回,故此,任意一个局部对象,通过返回其引用的方式,可以在其它任何对象中使用,即便创建此对象的对象已经销毁,该对象由于还有活着的引用存在,而存在。js借鉴的java语法,与此类似。归根到底,系统创建的对象都存在与一个队列中,对每个对象都有引用计数,直到引用为0即销毁。A对象中创建了B对象,A中只保存B的引用变量,而不包含B本身。把这些搞明白了,闭包只是个概念,没什么值得深入研究的。

三、闭包的用途:

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

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

  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),这时一定要小心,不要随便改变父函数内部变量的值。

五、闭包的使用场景

1.如上面举的例子, 闭包通常用来创建内部变量,使得这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作。

保护函数内的变量安全:如迭代器、生成器。在内存中维持变量:如果缓存数据、柯里化

2. 循环绑定事件(闭包允许内层函数引用父函数中的变量,但是该变量是最终值):

示例:

/**

* <body>

* <ul>

* <li>one</li>

* <li>two</li>

* <li>three</li>

* <li>one</li>

* </ul>

*/

var lists = document.getElementsByTagName('li');

for(var i = 0 , len = lists.length ; i < len ; i++){

lists[ i ].onmouseover = function(){

alert(i);

};

}

你会发现当鼠标移过每一个<li&rt;元素时,总是弹出4,而不是我们期待的元素下标。这是为什么呢?注意事项里已经讲了(最终值)。显然这种解释过于简单,当mouseover事件调用监听函数时,首先在匿名函数( function(){ alert(i); })内部查找是否定义了 i,结果是没有定义;因此它会向上查找,查找结果是已经定义了,并且i的值是4(循环后的i值);所以,最终每次弹出的都是4。

解决方法一:

var lists = document.getElementsByTagName('li');

for(var i = 0 , len = lists.length ; i < len ; i++){

(function(index){

lists[ index ].onmouseover = function(){

alert(index);

};

})(i);

}

解决方法二:

var lists = document.getElementsByTagName('li');

for(var i = 0, len = lists.length; i < len; i++){

lists[ i ].$$index = i; //通过在Dom元素上绑定$$index属性记录下标

lists[ i ].onmouseover = function(){

alert(this.$$index);

};

}

解决方法三:

function eventListener(list, index){

    list.onmouseover = function(){

        alert(index);

    };

}

var lists = document.getElementsByTagName('li');

for(var i = 0 , len = lists.length ; i < len ; i++){

    eventListener(lists[ i ] , i);

}

3. 匿名函数:

匿名函数最大的用途是创建闭包(这是JavaScript语言的特性之一),并且还可以构建命名空间,以减少全局变量的使用。

示例三:

var oEvent = {};

(function(){

var addEvent = function(){ /*代码的实现省略了*/ };

function removeEvent(){}

oEvent.addEvent = addEvent;

oEvent.removeEvent = removeEvent;

})();

在这段代码中函数addEvent和removeEvent都是局部变量,但我们可以通过全局变量oEvent使用它,这就大大减少了全局变量的使用,增强了网页的安全性。 我们要想使用此段代码:oEvent.addEvent(document.getElementById('box') , 'click' , function(){});

番外思考题

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

代码片段一。

  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()());


php 连接库闭包 php 连接库闭包

  • 2011年08月11日 16:19
  • 1003B
  • 下载

尚硅谷——JavaScript闭包

  • 2018年01月31日 10:56
  • 423KB
  • 下载

闭包(Java中的闭包)

闭包Java中的闭包 What 简单理解 WHY HOW Java中的闭包 内部类 局部内部类 匿名内部类 闭包(Java中的闭包):What 闭包是指可以包含自由(未绑定到特定对象)变量的代码块;这...
  • yztbydh
  • yztbydh
  • 2017-07-28 17:20:47
  • 2191

闭包经典面试题

闭包应该是前段面试中经常碰到的面试题,很多人都会在这个问题上被问住。如果想要弄清楚就要掌握闭包的概念; 首先看面试题: for (var i = 1; i   setTimeout...
  • donggx
  • donggx
  • 2017-04-14 14:13:28
  • 8455

到底什么是闭包

感觉楼里大部分回答太复杂了,过于理论化,文绉绉地绕来绕去,没抓住本质和精髓。抄书谁不会啊?其实闭包没那么复杂。 最简洁、直击要害的回答,我能想到的分别有这么三句(版权属于 @张恂老师 ): 1、...
  • wy_Blog
  • wy_Blog
  • 2017-02-25 22:13:49
  • 2315

Java 闭包机制

java闭包机制,它的实现需要两个部分闭包类(暂时称呼)+接口。闭包类:它是一个可以被调用的对象。它包含了一些作用域的内容(可以是参数,方法),它会自动拥有一个指向外部类的引用,通过它可以访问外部类的...
  • qq_23589445
  • qq_23589445
  • 2015-11-01 19:47:53
  • 1354

C# 闭包解析

背景知识 你必须了解:引用类型、值类型、引用、对象、值类型的值(简称值)。 关于引用、对象和值在内存的分配有如下几点规则: •对象分配在堆中。 •作为字段的引用分配在堆中(内嵌在对象中)...
  • cjolj
  • cjolj
  • 2017-03-08 10:46:09
  • 1090

Swift详解之四-------妈妈再也不用担心我的闭包了

妈妈再也不用担心我的闭包了 swift中闭包是一个很强大的东西,闭包是自包含的函数代码块,可以在代码中被传递和使用。跟C 和 Objective-C 中的代码块(blocks)很相似 。这个大家必须...
  • u010586842
  • u010586842
  • 2015-08-20 23:06:40
  • 2548

什么是闭包,闭包的作用与好处是什么,何时使用闭包,对闭包的改进

闭包:外部函数定义的内部函数就是闭包。 闭包的作用及好处:闭包给访问外部函数定义的内部变量创造了条件。也将关于函数的一切封闭到了函数内部,减少了全局变量,这也是闭包的真实含义。 与普通函数...
  • wzw_mzm
  • wzw_mzm
  • 2017-02-24 14:11:23
  • 2844

闭包的好处?

要理解闭包,首先必须理解Javascript特殊的变量作用域。 变量的作用域无非就是两种:全局变量和局部变量。 Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。...
  • qq_33567603
  • qq_33567603
  • 2016-10-12 11:53:57
  • 1737
收藏助手
不良信息举报
您举报文章:闭包
举报原因:
原因补充:

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