多层级理解闭包

闭包

闭包的概念困惑了我很久,记得当时我面试的时候最后一面有一个问题就是问题关于闭包的问题,然而到现在已经完全不记得当时的题目是啥了,但仍然能够回忆起当时不会的feel,虽然面试官非常友好的提醒了我应该用闭包,可是在我吭哧半天出不来的情况下,迷面试官还是耐心的给我讲了什么是闭包:有一个函数处理之后返回另一个函数,且只能执行一次。然后给我把当时的题写了一下,直到我出来都没有理解什么是闭包,那个题到底是什么题,要不是其他都答出来的话,估计都要挂。哎~一个菜鸟的心路历程。于是,闭包就成了我心里的梗。

今天凭借自己的理解,解释下什么是闭包。不免会参考网上各类大神的文章,各位看到请见谅。

闭包的理解是需要一个循序渐进的过程,下面我也会循序渐进从各个角度来阐述对闭包的不同理解,以便方便大家深度理解闭包。

第一梯队理解

我个人认为闭包之所以难以理解很重要的一点在于,很多概念我们在理解的过程中都会在潜意识里和这个概念本身的名词强度关联在一起在揣摩这个概念的意思,如果自己的理解和这个名词本身的字面意思看上去不那么相关的话,就会在内心产生巨大的怀疑感,不敢相信自己的理解是否正确,哪怕是正确的。所以在立即一个概念本身的含义过程中需要一个步骤就是将自己对概念的理解和名词本身找到某种莫名的连接方法就好理解了。

而闭包这个名词换做谁听上去都不知道是在说什么,这本身就给理解这个概念造成了很大的困惑,因为一个通俗易懂的代名词就可以很好地解释一个概念的50%了。比如变量就是变化的字面量,条件语句,分支语句大家一听就很好理解其概念是什么。所以首先大家需要在概念上给闭包建立一个初级的感性认识。一下这句话是我见到的简单易懂的一种解释。


  1. functions that return functions 

意思是:闭包就是一个函数,只不过这个函数是另一个函数的返回值。

没错,最表面上看似乎就是这样的。比如写一个闭包:


  1. function fn1() { 
  2.       var temp = 10; 
  3.       return function() { 
  4.           console.log(++temp); 
  5.       } 
  6.  } 
  7.  fn1()();  

上面的例子里return出来的那个function就是一个非常简单的闭包,表面上看和上面的定义语句差不多就是一个从函数里返回的函数。

第一梯队的理解到这接差不多了,虽然不正确,虽然很粗糙,但对形成一个感性认识应该是够了,总结一个第一梯队的认识,什么是闭包:

  • 一个函数
  • 被其他函数return出来的函数。

这个时候认识里面应该有这么一个概念,就是闭包和我们已经理解的一个概念应该差不多,那就是函数,没错刚开始就可以这么理解,闭包就是一个函数,是一个特殊的函数,就好像js中的方法也是函数一样。

第二梯队理解

有了第一梯队的认识,我们慢慢修正大脑中对闭包的认识。有的人理解闭包就是一个嵌套在函数里的函数,内部函数可以访问外部函数的数据而已。这么理解是不对的。看下面这段代码:


  1. function fn1() { 
  2.   var temp = 10; 
  3.   function fn2() { 
  4.       console.log(++temp); 
  5.   } 
  6.   fn2() 
  7. fn1()  

可是这时的fn1()无论执行多少次打印都是11,永远不会变,所以这还不是闭包,只有当你return出来一个内部function的时候才会形成一个闭包,闭包就是return出来的这个函数。这个内部函数可以close-over外部函数的变量直到内部的这个函数(闭包)结束掉。

这时我们再来看看第一梯队中的代码


  1. function fn1() { 
  2.       var temp = 10; 
  3.       return function() { 
  4.           console.log(++temp); 
  5.       } 
  6.  } 
  7.  vat func1 = fn1(); // func1就是一个闭包(就是fn1返回的函数)。 
  8.  func1(); // 打印11 
  9.  func1(); // 打印12  

这个时候func1是全局变量,但是打印的时候却访问的是fn1的局部变量temp并且,当fn1()函数执行完之后,temp的变量并没有被垃圾回收到仍然存在于内存中,这就是闭包的特点。也就是刚刚我们说的内部函数close-over外部函数的变量。理解这句话就可以很好的与闭包这两个字关联起来理解闭包这个概念了。

总结第二梯队理解:

  1. 闭包是一个有特定功能的函数。他是一个可以读取其他函数内部变量的一个函数。
  2. 因为在javascript中如果你想读取一个函数内的变量(通常称为局部变量)只有函数的子函数可以访问。
  3. 那么将这两个概念交叉理解,就可以简单的理解闭包就是一个定义在函数内部的函数,且可以访问函数里的局部变量的那个函数。
  4. 在没有闭包,我们没法访问函数内部的局部变量,有了闭包之后,我们就可以访问函数内部的局部变量了,等同于闭包解决了一个问题,那就是在函数内部和函数外部之间建立了一座桥梁。

第三梯队理解

这个时候我们可以看看官方定义的闭包:闭包是指那些能够访问独立(自由)变量的函数 (变量在本地使用,但定义在一个封闭的作用域中)。换句话说,这些函数可以“记忆”它被创建时候的环境。

再看另一个定义:那么什么是闭包呢?这里有两个定义。在计算机科学中(而不是数学中),一个闭包是一个函数或者一个函数的引用,以及他们所引用的环境信息(就像是一个表,这个表存储了这个函数中引用的每一个没有在函数内声明的变量)。

这两个定义中都有一个概念,第一个里“封闭的作用域”,第二个里“所引用的环境信息”。这里我们都可以用上面的close-over外部函数的变量暂时理解。

也就是闭包总是要有两个部分的:

  1. 一部分是一个函数。
  2. 另一个部分是被这个函数“包住”的(有的理解为“带走”的,或者是close-over住的)一些环境信息(可以理解环境信息就是变量),但是却不在这个函数中声明的变量表(称之为free variables或者outer variables)。

还有一个不是那么呆的定义:闭包允许你封装一些行为(函数就是行为),像其他对象一样将它传来传去(函数是first-class function),但是不论怎样,它仍然保持着对原来最初上下文的访问能力(它还能访问到 outer variables)。

这个时候的理解就比较抽象了,因为又涉及到作用域的概念,又是一个封闭的作用域。其实上面括号中有一段话(就像是一个表,这个表存储了这个函数中引用的每一个没有在函数内声明的变量),这个表就是在定义这个闭包的“闭”的范围有哪些。

第四梯队理解

闭包通过访问外部变量,一个闭包可以维持(keep alive)这些变量。在内部函数和外部函数的例子中,外部函数可以创建局部变量,并且最终退出;但是,如果任何一个或多个内部函数在它退出后却没有退出,那么内部函数就维持了外部函数的局部数据。

从技术上来讲,在JS中,每个function都是闭包,因为它总是能访问在它外部定义的数据。

目前我的水平也就理解到这里了,希望给大家有所帮助。

作者:anlin_yang

来源:51CTO

时间: 2024-08-31 08:55:31

多层级理解闭包的相关文章

JavaScript——以简单的方式理解闭包

      闭包,在一开始接触JavaScript的时候就听说过.首先明确一点,它理解起来确实不复杂,而且它也非常好用.那我们去理解闭包之前,要有什么基础 呢?我个人认为最重要的便是作用域(lexical scope),如果对作用域和作用域链不理解的同学最好自己先去学一学,再回过头来,理解闭包,就更加轻松. 下面便直接进入主题. 我们知道一个函数是有作用域的,在函数内部定义的局部变量只有在函数内部才可以访问的到.一旦函数访问结束被销毁,局部变量随之也会销毁,无法 通过任何方式再次访问局部变量,除

让你一句话理解闭包(简单易懂)_javascript技巧

接触javascript很久了,每次理解闭包都似是而非,最近在找Web前端的工作,所以需要把基础夯实一下. 本文是参照了joy_lee的博客 闭包 在她这篇博客的基础上以批注的形式力争把我的理解阐述出来,如果有不当之处,欢迎批评指正. <高级程序设计>上,这样说:当在函数内部定义了其他函数时候,就创建了闭包.闭包有权访问包含函数内部的所有变量. (这句话怎么理解呢?照这句话理解的话,闭包就是一个嵌套函数嘛!嵌套函数对包含它的函数的变量当然可以访问,这是没有问题的.) 一般来说,内部函数是能够访

全面理解闭包机制_基础知识

var foo = "Hello"; var c =(function a() { function b(){ var bar = " World"; alert(foo + bar); return bar; } return b; })()(); alert(foo + c); 本实例弹出两次hello world: 一.什么是闭包? "官方"的解释是:所谓"闭包",指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通

《数据科学:R语言实现》——1.6 理解闭包

1.6 理解闭包 函数是R语言的一级成员.换句话说,你可以给一个函数传递另一个函数.在之前的教程中,我们展示了如何创建一个被命名的函数.然而,我们也可以创建一个不带名字的函数,即闭包(也就是匿名函数).在本教程中,我们会展示如何在标准函数中使用闭包. 准备工作 确保你已经在操作系统中安装了R语言,完成了之前的步骤. 实现步骤 执行下列步骤,在函数中创建闭包. 1.让我们回顾一下被命名的函数是如何工作的: 2.现在,让我们使用同样的步骤,通过闭包来求两个变量的和: 3.我们也可以在另一个函数中调用

js学习之----深入理解闭包_基础知识

闭包算是js里面比较不容易理解的点,尤其是对于没有编程基础的人来说. 其实闭包要注意的就那么几条,如果你都明白了那么征服它并不是什么难事儿.下面就让我们来谈一谈闭包的一些基本原理.  闭包的概念 一个闭包就是一个函数和被创建的函数中的作用域对象的组合.(作用域对象下面会说) 通俗一点的就是 " 只要一个函数中嵌套了一个或多个函数,那么我们就可以称它们构成了闭包. " 类似这样: function A() { var i = 5; return function() { console.

封装网络请求类来理解闭包

import UIKit import Alamofire enum MethodType { case get case post } class NetworkTools { class func requestData(_ type : MethodType, URLString : String, parameters : [String : Any]? = nil, finishedCallback : @escaping (_ result : Any) -> ()) { // 1.

理解闭包 js回收机制

为什么要有回收机制?why? 打个比方,我有一个内存卡,这个内存是8G的,我把文件,视频,音乐,都保存到了这个内存卡,随着我的储存的内容越来越多,这个内存卡已经保存不了了,如果我还想再把其他的文件保存到这个内存卡就需要删除一些文件,但是这些被删除的文件是我们自己手动删除的对吧,手动删除就相当于js中的delete. 在这些程序语言中同样也会出现这些问题,对,内存!我们声明的任何变量都需要消耗内存,这些变量越多运行的速度也会越慢.当然不只是变量,代码中的任何东西.这些语言的设计者为了解决这些问题,

深入理解js闭包

深入理解js闭包 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码

js中的闭包之我理解

闭包是一个比较抽象的概念,尤其是对js新手来说.书上的解释实在是比较晦涩,对我来说也是一样. 但是他也是js能力提升中无法绕过的一环,几乎每次面试必问的问题,因为在回答的时候.你的答案的深度,对术语的理解以及js内部解释器的运作 方式的描述,都是可以看出你js实际水平的.即使你没答对,也能让考官对你的水平有个评估.那么我先来说说我对js中的闭包的理解. 闭包是很多语言都具备的特性,在js中,闭包主要涉及到js的几个其他的特性:作用域链,垃圾(内存)回收机制,函数嵌套,等等. 在理解闭包以前.最好