如何理解闭包

理解Python闭包概念 其实问题的关键就在于在返回闭包列表fs之前for循环的变量的值已经发生改变了,而且这个改变会影响到所有引用它的内部定义的函数。运行的结果也说明了闭包函数中引用的父函数中local variable既不具有C++中的全局变量的性质也没有static变量的行为。函数my_func一旦返回,那么内部定义的函数func便是一个闭包,其中引用的变量j成为一个只和具体闭包相关的自由变量。应该怎么正确的理解呢?C++中有static关键字,函数中的static关键字定义的变量独立于函数之外,而且会保留函数中值的变化。 阅读详情
[本文转自:http://www.jb51.net/article/24101.htm]

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

一、变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。


Js代码

  var n=999;

  function f1(){
    alert(n);
  }

  f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

Js代码

  function f1(){
    var n=999;
  }

  alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

Js代码

  function f1(){
    n=999;
  }

  f1();

  alert(n); // 999

--------------------------------------------------------------------------------------------------------

二、如何从外部读取局部变量?

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

那就是在函数的内部,再定义一个函数。

Js代码

  function f1(){

    n=999;

    function f2(){
      alert(n); // 999
    }

  }

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1 就是不可见的。这就是Javascript语言特有的“链式作用域”结构(chain scope),

子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!


Js代码

  function f1(){

    n=999;

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

--------------------------------------------------------------------------------------------------------

三、闭包的概念

上一节代码中的f2函数,就是闭包。

各种专业文献上的“闭包”(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

--------------------------------------------------------------------------------------------------------b

四、闭包的用途

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

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


Js代码

  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),这时一定要小心,不要随便

改变父函数内部变量的值。

--------------------------------------------------------------------------------------------------------

六、思考题

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

Js代码
  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
     };
    }
};
alert(object.getNameFunc()());
//The Window

--------------------------------------------------------------------------------------------------------
JavaScript闭包例子

function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
}
innerFun()

上面的代码是错误的.innerFun()的作用域在outerFun()内部,所在outerFun()外部调用它是错误的.

改成如下,也就是闭包:

Js代码

function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
return innerFun; //注意这里
}
var obj=outerFun();
obj(); //结果为1
obj(); //结果为2
var obj2=outerFun();
obj2(); //结果为1
obj2(); //结果为2

什么是闭包:

当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们.

--------------------------------------------------------------------------------------------------------

再来看一个例子

Js代码

function outerFun()
{
var a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);

结果是 0,4 . 因为在函数内部使用了var关键字 维护a的作用域在outFun()内部.

再看下面的代码:

Js代码

function outerFun()
{
//没有var
a =0;
alert(a);
}
var a=4;
outerFun();
alert(a);

结果为 0,0 真是奇怪,为什么呢?

作用域链是描述一种路径的术语,沿着该路径可以确定变量的值 .当执行a=0时,因为没有使用var关键字,因此赋值操作会沿着作用域链到var a=4; 并改变其值. 


[摘自:http://segmentfault.com/a/1190000002778015?utm_source=Douban&utm_medium=shareLink&utm_campaign=socialShare]

闭包的运用

我们来看看闭包的用途。事实上,通过使用闭包,我们可以做很多事情。比如模拟面向对象的代码风格;更优雅,更简洁的表达出代码;在某些方面提升代码的执行效率。

1. 匿名自执行函数

我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,比如UI的初始化,那么我们可以使用闭包:

//将全部li字体变为红色
(function(){    
    var els = document.getElementsByTagName('li');
    for(var i = 0,lng = els.length;i < lng;i++){
        els[i].style.color = 'red';
    }    
})();  

我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,
因此els,i,lng这些局部变量在执行完后很快就会被释放,节省内存!
关键是这种机制不会污染全局对象。

2. 实现封装/模块化代码

var person= function(){    
    //变量作用域为函数内部,外部无法访问    
    var name = "default";       

    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();
console.log(person.name);//直接访问,结果为undefined    
console.log(person.getName());  //default 
person.setName("jozo");    
console.log(person.getName());  //jozo

3. 实现面向对象中的对象
这样不同的对象(类的实例)拥有独立的成员及状态,互不干涉。虽然JavaScript中没有类这样的机制,但是通过使用闭包,
我们可以模拟出这样的机制。还是以上边的例子来讲:

function Person(){    
    var name = "default";       

    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
};    


var person1= Person();    
print(person1.getName());    
john.setName("person1");    
print(person1.getName());  // person1  

var person2= Person();    
print(person2.getName());    
jack.setName("erson2");    
print(erson2.getName());  //person2

Person的两个实例person1 和 person2 互不干扰!因为这两个实例对name这个成员的访问是独立的 。

垃圾回收机制

说到内存管理,自然离不开JS中的垃圾回收机制,有两种策略来实现垃圾回收:标记清除 和 引用计数;

标记清除:垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记,然后,它会去掉环境中的变量的标记和被环境中的变量引用的变量的标记,此后,如果变量再被标记则表示此变量准备被删除。 2008年为止,IE,Firefox,opera,chrome,Safari的javascript都用使用了该方式;

引用计数:跟踪记录每个值被引用的次数,当声明一个变量并将一个引用类型的值赋给该变量时,这个值的引用次数就是1,如果这个值再被赋值给另一个变量,则引用次数加1。相反,如果一个变量脱离了该值的引用,则该值引用次数减1,当次数为0时,就会等待垃圾收集器的回收。

这个方式存在一个比较大的问题就是循环引用,就是说A对象包含一个指向B的指针,对象B也包含一个指向A的引用。 这就可能造成大量内存得不到回收(内存泄露),因为它们的引用次数永远不可能是 0 。早期的IE版本里(ie4-ie6)采用是计数的垃圾回收机制,闭包导致内存泄露的一个原因就是这个算法的一个缺陷。

我们知道,IE中有一部分对象并不是原生额javascript对象,例如,BOM和DOM中的对象就是以COM对象的形式实现的,而COM对象的垃圾回收机制采用的就是引用计数。因此,虽然IE的javascript引擎采用的是标记清除策略,但是访问COM对象依然是基于引用计数的,因此只要在IE中设计COM对象就会存在循环引用的问题!

举个栗子:

window.onload = function(){
    var el = document.getElementById("id");
    el.onclick = function(){
        alert(el.id);
    }
}

这段代码为什么会造成内存泄露?

el.onclick= function () {
    alert(el.id);
};

执行这段代码的时候,将匿名函数对象赋值给el的onclick属性;然后匿名函数内部又引用了el对象,存在循环引用,所以不能被回收;

解决方法:

window.onload = function(){
    var el = document.getElementById("id");
    var id = el.id; //解除循环引用
    el.onclick = function(){
        alert(id); 
    }
    el = null; // 将闭包引用的外部函数中活动对象清除
}

闭包的优缺点

优点:

  • 可以让一个变量常驻内存 (如果用的多了就成了缺点
  • 避免全局变量的污染
  • 私有化变量

缺点

  • 因为闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存
  • 引起内存泄露

铁路场景雷达点云目标识别与追踪系统 本文介绍了一种基于毫米波雷达的铁路货运车站安全监控系统。该系统采用分布式架构,通过多个毫米波雷达节点采集点云数据,经过坐标转换、多雷达融合等处理后,利用机器学习算法实现列车、行人等目标的实时识别与追踪。系统包含数据采集层、处理层、目标识别层、追踪层、预警决策层和可视化层,能够克服传统视频监控受环境影响大的缺点,实现全天候可靠监测。文中详细展示了雷达数据解析和点云预处理的代码实现,包括坐标转换、数据格式解析和体素网格滤波等关键技术。该系统可有效预警铁路场景下的碰撞风险,提升货运车站的安全管理水平。 阅读详情

相关推荐

RaiDrive+AList保姆级教程:5分钟搞定OneDrive/百度网盘挂载到本地(附WebDAV配置)

本文提供RaiDrive+AList的保姆级教程,5分钟内实现将OneDrive/百度网盘挂载到本地的详细步骤,包括WebDAV配置。通过AList统一转换云存储协议,RaiDrive虚拟磁盘挂载,显著提升多网盘管理效率,适合需要跨平台操作文件的用户。

weixin_28331555的博客 456

闭包概念理解

关于js语言中闭包的理解及作用域

smallSun0110的博客 1945

Figure 03人形机器人与Helix端到端控制系统:具身智能突破深度解析

2026年5月,Figure AI的Figure 03人形机器人在一场震撼业界的直播中完成了长达200小时的连续全自动作业,分拣近25万个包裹,零故障。这一里程碑式的成就标志着人形机器人正式从「实验室展示」迈入「规模化商用」阶段。本文深入剖析Figure 03的核心技术——Helix端到端神经网络控制系统,包括System 0/1/2三层架构、视觉运动策略、全身协同控制等关键技术,并提供完整的Python/Go代码示例,帮助开发者理解具身智能的核心原理与实现路径。关键词。

shao.bing的专栏 993

如何理解闭包?

闭包

qq_38361229的博客 324

PSM-DID实战指南:Stata代码解析与案例应用

本文详细解析PSM-DID方法在Stata中的实战应用,从理论到代码实现全面覆盖。通过倾向得分匹配(PSM)和双重差分(DID)的结合,有效解决政策评估中的选择偏差问题。文章提供完整的Stata命令代码、样例数据处理技巧和案例应用,帮助研究者准确评估政策效果。

vulkan6gpu的博客 793

饥荒联机版Mod开发——modmain环境与API深度解析

本文深入解析饥荒联机版Mod开发中的modmain.lua环境与核心API,详细讲解环境表构建原理、API注册与调用时机,并提供高级开发技巧与最佳实践。通过源码分析和实际案例,帮助开发者掌握Mod开发核心技术,解决常见问题,提升开发效率与代码质量。

weixin_30312563的博客 433

闭包的理解?什么是闭包?

官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。(函数就是一个表达式)JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。我们之前常说的一些什么保持变量内部私有性,避免了全局变量因为命名冲突造成的全局污染;支持跨作用域访问延伸变量作用范围,其实我们细想一下这些都是函数的作用范围让外部访问函数内部变量成为可能;

Hushingiwkw的博客 504

倍福EL6002做RS232通信获取称重数据..

本文介绍EL6002模块通过RS232自由口通信协议获取从站数据。具体数据对照说明手册即可。

weixin_41883890的博客 1012

闭包是什么?五分钟带你了解闭包

你可以在一个函数里面嵌套另外一个函数。嵌套(内部)函数对其容器(外部)函数是私有的。它自身也形成了一个闭包。一个闭包是一个可以自己拥有独立的环境与变量的的表达式(通常是函数,因为ES6有了块级作用域的概念)。可以先点击上面链接查看MDN对闭包的讲述。闭包是指有权访问另一个函数作用域中的变量的函数。这样闭包的作用就很明显了可以在函数的外部访问到函数内部的局部变量。让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。

寒烟说的博客 3万+

RT-DETR改进策略【卷积层】| CGblock 内容引导网络 利用不同层次信息,提高多类别分类能力 (含二次创新)

本文记录的是利用中的模块优化的目标检测网络模型。通过局部特征提取器、周围环境提取器、联合特征提取器和全局环境提取器来提取局部特征、周围环境和全局环境信息,充分利用不同层次的信息。本文将其应用到中,并进行二次创新,使网络能够更好的处理多类别目标的分类能力。CGNet: A Light-Weight Context Guided Network for Semantic Segmentation1️⃣ 首先通过局部特征提取器floc(∗)floc(*)floc(∗)和周围环境提取器fsur(∗)f_{sur }

Limiiiing的博客 1350

21天教你学会PCIe专栏(21)--项目实例:构建一个基于 PCIe 的 NVMe SSD 阵列存储系统

构建一个高性能的 NVMe SSD 阵列存储系统,利用 PCIe 连接多块 NVMe SSD,实现高带宽和低延迟的数据存储。该系统将支持多种存储配置,如 RAID 0、RAID 1 和 RAID 5,以满足不同的性能和可靠性需求。通过上述步骤,你可以构建一个基于 PCIe 的 NVMe SSD 阵列存储系统。这个系统能够提供高带宽和低延迟的数据存储,并支持多种 RAID 配置以满足不同的性能和可靠性需求。

xiaoheshang_123的博客 200

对闭包的理解

对闭包的理解,简单的理解就是函数中套了一个函数,内层函数可以访问外层函数中的变量。闭包的优点,闭包的缺点

zzdjdbd的博客 279

SPICE仿真软件:HSPICE_(20).HSPICE仿真结果的后处理

HSPICE仿真结果的后处理是一个多步骤的过程,包括读取结果文件、可视化、分析和导出。通过使用命令行工具、Python脚本和HSPICE内置工具,可以高效、准确地完成这些任务。Python脚本的灵活性和强大的数据分析能力使其成为后处理的理想选择。自动化处理可以显著提高工作效率,减少人为错误,而高级分析方法可以更深入地理解仿真结果,为电路设计提供有力支持。

kkchenjj的博客 1382

js闭包的理解

百度百科对闭包的定义闭包就是能够读取其他函数内部变量的函数。在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

z1093541823的博客 1850

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

对JavaScript中闭包的理解

之前对于闭包这个概念的理解都是模糊的,只是单纯的知道闭包的作用: 1. 可以在函数的外部访问到函数内部的局部变量。 2. 让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。  而这几天通过各种资料和博客的学习,自认对闭包的概念和原理有了一定的了解,所以来分享一下我的心得。如果文中有什么不当之处,请多多谅解,并给与指正。谢谢!什么是闭包?在维基百科中的描述是: 在计算机科学中,闭包(英

王宜明的个人博客 6797

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

谈谈对闭包的理解

createComparitionFunction()的活动对象并不能在它执行完毕后销毁,因为匿名函数的作用域链中仍然有对它的引用,因为匿名函数的作用域链中仍然有对他的引用。在createComparitionFunction()执行完毕之后,其上下文执行的作用域链就会销毁,但是它的活动对象仍然会保留在内存之中,直到匿名函数被销毁。是最外层的上下文,在浏览器中,全局上下文就是我们常说的window对象,因此通过var定义的全局变量和函数都会成为window对象的属性和方法。每个函数调用都有自己的上下文。

m0_67457135的博客 1176

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

什么是闭包,对闭包的理解,闭包的用途及优缺点

什么是闭包,对闭包的理解,闭包的用途、优缺点及注意事项

weixin_48644617的博客 3万+

关于对闭包的理解以及实例

闭包,在面试时经常被问到,也看了很多文章,书籍,但是对于闭包的理解还是停留在“在一个函数内创建另一个函数,以此可以访问使用函数中的变量”,在这总结一下加深理解。 首先,理解闭包得先了解作用域链。 1、执行环境及作用域 ...

qq_35423431的博客 306

JavaScript 什么是闭包,对闭包的理解

闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。比如,下面是之前展示的createComparisonFunction()函数,注 意其中加粗的代码:这里加粗的代码位于内部函数(匿名函数)中,其中引用了外部函数的变量。在这个内部函数被返回并在其他地方被使用后,它仍然引用着那个变量。这是因为内部函数的作用域链包含 createComparisonFunction()函数的作用域。要理解为什么会这样,可以想想第一次调用这个函数 时会发生什么。

m0_61362703的博客 573

关于闭包的理解

闭包 闭包的概念 闭包函数:声明一个在函数中的函数,叫做闭包函数 闭包:内部函数总是可以访问其所在的外部函数中声明的变量和参数,即使在其外部函数被返回了之后 闭包的特点 让外部访问函数内部成为可能 局部变量会常驻在内存中 可以避免使用全局变量,防止全局变量污染 会造成内存的泄露(有一块内存空间被长期占用,而不被释放) 闭包的创建 闭包就是可以创建一个独立的环境,每个闭包里面的环境都是独立的,互不干扰。闭包会发生内存泄漏,每次外部函数执行的时候,外部函数的引用地址不同,都会重新创建一个新的地址。但凡

这可不是一般的博客,这是王维诗里的博客 879

JS中闭包的理解

什么是闭包? 闭包其实就是一个函数,什么样的函数?能够访问另一个函数作用域中变量的函数。 为什么要有闭包? 在回答这个问题之前,我先提一个假设,我们都知道在内部的函数可以访问外部函数的变量,假设现在就是有这么一个需要,需要外部环境来访问函数的内部变量,怎么办?这时就要用到闭包,这就要牵扯到闭包的实现原理,即作用域链的工作。每当函数创建时,JS底层都会在其执行环境下创建一个作用域链,这个作用域...

yanggreater的博客 219

如何理解及使用闭包

那么闭包到底是啥? 根据MDN官方文档是定义:闭包 = 函数 + 周围状态(环境的)的引用 。所以闭包不等于是函数, 为了表述的方便,我称之为闭包结构。 先来个超简单的栗子 var name = 'lufei' function fn() { console.log(name) } fn+name 就形成了一个闭包的结构 function ff() { var name = 'lufei' return function fn() { return name } } //这.

JINGinC的博客 1348

闭包理解

关于闭包的理解,写的很详细

qq_39213643的博客 186

函数闭包理解

概念 闭包函数:声明在一个函数中的函数,叫做闭包函数。 闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。 特点 让外部访问函数内部变量成为可能; 局部变量会常驻在内存中; 可以避免使用全局变量,防止全局变量污染; 会造成内存泄漏(有一块内存空间被长期占用,而不被释放) 理解闭包自行代入这句话 结论:闭包找到的是同一地址中父级函数中对应变量...

weixin_43827424的博客 462
上一篇: Media Queries媒体查询相关样式
下一篇: flash遮挡div的问题
阿榄
博客等级 码龄18年 31粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值