关于闭包及变量回收问题

本文的诞生,源自近期打算做的一个关于javascript中的闭包的专题,由于需要解析闭包对垃圾回收的影响,特此针对不同的javascript引擎,做了相关的测试。

为了能从本文中得到需要的知识,看本文前,请明确自己知道闭包的概念,并对垃圾回收的常用算法有一定的了解。

问题的提出

假设有如下的代码:

function outer() {
    var largeObject = LargeObject.fromSize('100MB');

    return function() {
        console.log('inner');
    };
}
var inner = outer();

在这一段代码中,outer函数和inner函数间会形成一个闭包,致使inner函数能够访问到largeObject,但是显然inner并没有访问largeObject,那么在闭包中的largeObject对象是否能被回收呢?

如果引入更复杂的情况:

function outer() {
    var largeObject = LargeObject.fromSize('100MB');
    var anotherLargeObject = LargeObject.fromSize('100MB');

    return function() {
        largeObject.work();
        console.log('inner');
    };
}
var inner = outer();

首先一个显然的概念是largeObject肯定不能被回收,因为inner确实地需要使用它。但是anotherLargeObject又能不能被回收呢?它将跟随largeObject一起始终存在,还是和largeObject分离,独立地被回收呢?

测试方法

带着这个疑问,对现有的几款现代javascript引擎分别进行了测试,参与测试的有:

  • IE8自带的JScript.dll
  • IE9自带的Chakra
  • Opera 11.60自带的Carakan
  • Chrome 16.0.912.63自带的V8(3.6.6.11)
  • Firefox 9.0.1自带的SpiderMonkey

测试的基本方案是,使用类似以下的代码:

function outer() {
    var largeObject = LargeObject.fromSize('100MB');

    return function() {
        debugger;
    };
}
var inner = outer();

通过各浏览器的开发者工具(Developer Tools、Firebug、Dragonfly等),在断点处停止javascript的执行,并通过控制台或本地变量查看功能检查largeObject的值,如果其值存在,则认为GC并没有回收该对象。

对于部分浏览器(特别是IE),考虑到对脚本执行有2种模式(执行模式和调试模式,IE通过开发者工具的Script面板中的“Start Debugging”按钮切换),在调试模式下才会命中断点,但是调试模式下可能存在不同的引擎优化方案,因此采用内存比对的方式进行测试。即打开资源浏览器,在var inner = outer();一行后强制执行一次垃圾回收(IE使用window.CollectGarbage();Opera使用window.opera.collect();),查看内存的变化。如果内存始终有100MB的占用,没有明显的下降现象,则认为GC并没有回收该对象。

对于用例的设计,由于从ECMAScript标准中可以得知,所有的变量访问是通过一个LexicalEnvironment对象进行的,因此目标在于在不同的LexicalEnvironment结构下进行测试。从标准中,搜索LexicalEnvironment不难得出能够改变LexicalEnvironment结构的情况有以下几种:

  1. 进入一个函数。
  2. 进入一段eval代码。
  3. 使用with语句。
  4. 使用catch语句。

因此以下将针对这4种情况,进行多用例的测试。

测试过程级结果

基本测试
使用代码
function outer() {
    var largeObject = LargeObject.fromSize('100MB');

    return function() {
        debugger;
    };
}
var inner = outer();
inner();
测试结果
  • JScript.dll – 不回收,内存无下降趋势。
  • Chakra – 回收,内存会恢复到outer函数执行前的状态。
  • Carakan – 不回收,内存无下降趋势。
  • V8 – 回收,访问largeObject抛出ReferenceError。
  • SpiderMonkey – 回收,访问largeObject得到undefined。
结论

当一个函数outer返回另一个函数inner时,Chakra、V8和SpiderMonkey会对outer中声明,但inner中不使用的变量进行回收,其中V8直接将变量从LexicalEnvironment上解除绑定,而SpiderMonkey仅仅将变量的值设为undefined,并不解除绑定。

多个变量的情况
使用代码
function outer() {
    var largeObject = LargeObject.fromSize('100MB');
    var anotherLargeObject = LargeObject.fromSize('100MB');

    return function() {
        largeObject;
        debugger;
    };
}
var inner = outer();
inner();
测试结果
  • JScript.dll – 不回收,内存无下降趋势。
  • Chakra – 回收anotherLargeObject,内存会回到outer调用前并增加100MB左右。
  • Carakan – 不回收,内存无下降趋势。
  • V8 – 回收,访问largeObject能得到正确的值,访问anotherLargeObject抛出ReferenceError。
  • SpiderMonkey – 回收,访问largeObject能得到正确的值,访问anotherLargeObject得到undefined。
结论

当一个LexicalEnvironment上存在多个变量绑定时,Chakra、V8和SpiderMonkey会针对不同的变量判断是否有被使用,该判断方法是扫描返回的函数inner的源码来实现的,随后会将没有被inner使用的变量从LexicalEnvironment中解除绑定(同样的,SpiderMonkey不解除绑定,仅赋值为undefined),而剩下的变量继续保留。

eval的影响
使用代码
function outer() {
    var largeObject = LargeObject.fromSize('100MB');

    return function() {
        eval('');
        debugger;
    };
}
var inner = outer();
inner();
测试结果
  • JScript.dll – 不回收,内存无下降趋势。
  • Chakra – 不回收,内存无下降趋势。
  • Carakan – 不回收,内存无下降趋势。
  • V8 – 不回收,访问largeObject可得到正确的值。
  • SpiderMonkey – 不回收,访问largeObject可得到正确的值。
结论

如果返回的inner函数中有使用eval函数,则不LexicalEnvironment中的任何变量进行解除绑定的操作,保留所有变量的绑定,以避免产生不可预期的结果。

间接调用eval
使用代码
function outer() {
    var largeObject = LargeObject.fromSize('100MB');

    return function() {
        window.eval('');
        debugger;
    };
}
var inner = outer();
inner();
测试结果
  • JScript.dll – 不回收,内存无下降趋势。
  • Chakra – 回收,内存会恢复到outer函数执行前的状态。
  • Carakan – 不回收,内存无下降趋势。
  • V8 – 回收,访问largeObject抛出ReferenceError。
  • SpiderMonkey – 回收,访问largeObject得到undefined。
结论

由于ECMAScript规定间接调用eval时,代码将在全局作用域下执行,是无法访问到largeObject变量的。因此对于间接调用eval的情况,各javascript引擎将按标准的方式进行处理,无视该间接调用eval的存在。

同样的,对于new Function('return largeObject;')这种情形,由于标准规定new Function创建的函数的[[Scope]]是全局的LexicalEnvironment,因此也无法访问到largeObject,所有引擎都参照间接调用eval的方式,选择无视Function构造函数的调用。

多个嵌套函数
使用代码
function outer() {
    var largeObject = LargeObject.fromSize('100MB');

    function help() {
        largeObject;
        // eval('');
    }

    return function() {
        debugger;
    };
}
var inner = outer();
inner();
测试结果
  • JScript.dll – 不回收,内存无下降趋势。
  • Chakra – 不回收,内存无下降趋势。
  • Carakan – 不回收,内存无下降趋势。
  • V8 – 不回收,访问largeObject可得到正确的值。
  • SpiderMonkey – 不回收,访问largeObject可得到正确的值。
结论

不仅仅是被返回的inner函数,如果在outer函数中定义的嵌套的help函数中使用了largeObject变量(或直接调用eval),也同样会造成largeObject变量无法回收。因此javascript引擎扫描的不仅仅是inner函数的源码,同样扫描了其他所有嵌套函数的源码,以判断是否可以解除某个特定变量的绑定。

使用with表达式
使用代码
function outer() {
    var largeObject = LargeObject.fromSize('100MB');
    var scope = { o: LargeObject.fromSize('100MB') };

    with (scope) {
        return function() {
            debugger;
        };
    }
}
var inner = outer();
inner();
测试结果
  • JScript.dll – 不回收,内存无下降趋势。
  • Chakra – 回收largeObject,但不回收scope.o,内存恢复至outer函数被调用前并增加100MB左右(无法得知scope是否被回收)。
  • Carakan – 不回收,内存无下降趋势。
  • V8 – 不回收,访问largeObject和scope以及o均可得到正确的值。
  • SpiderMonkey – 回收largeObject和scope,访问该2个变量均得到undefined,不回收o,可得到正确的值。
结论

当有with表达式时,V8将会放弃所有变量的回收,保留LexicalEnvironment中所有变量的绑定。而SpiderMonkey则会保留由with表达式生成的新的LexicalEnvironment中的所有变量的绑定,而对于outer函数生成的LexicalEnvironment,按标准的方式进行处理,尽可能解除其中的变量绑定。

使用catch表达式
使用代码
function outer() {
    var largeObject = LargeObject.fromSize('100MB');

    try {
        throw { o: LargeObject.fromSize('100MB'); }
    }
    catch (ex) {
        return function() {
            debugger;
        };
    }
}
var inner = outer();
inner();
测试结果
  • JScript.dll – 不回收,内存无下降趋势。
  • Chakra – 回收largeObject和ex,内存会恢复到outer函数被调用前的状态。
  • Carakan – 不回收,内存无下降趋势。
  • V8 – 仅回收largeObject,访问largeObject抛出ReferenceError,但仍可访问到ex。
  • SpiderMonkey – 仅回收largeObject,访问largeObject得到undefined,但仍可访问到ex。
结论

catch表达式虽然会增加一个LexicalEnvironment,但对闭包内变量的绑定解除算法几乎没有影响,这源于catch生成的LexicalEnvironment仅仅是追加了被catch的Error对象一个绑定,是可控的(相对的with则不可控),因此对变量回收的影响也可以控制和优化。但对于新生成并添加了Error对象的LexicalEnvironment,V8和SpiderMonkey均不会进一步优化回收,而Chakra则会对该LexicalEnvironment进行处理,如果其中的Error对象可以回收,则会解除其绑定。

嵌套函数中声明的同名变量
使用代码
function outer() {
    var largeObject = LargeObject.fromSize('100MB');

    return function(largeObject /* 或在函数体内声明 */) {
        // var largeObject;
    };
}
var inner = outer();
inner();
测试结果
  • JScript.dll – 不回收,内存无下降趋势。
  • Chakra – 回收,内存会恢复到outer函数被调用前的状态。
  • Carakan – 不回收,内存无下降趋势。
  • V8 – 回收,内存会恢复到outer函数被调用前的状态。
  • SpiderMonkey – 回收,内存会恢复到outer函数被调用前的状态。
结论

嵌套函数中有与外层函数同名的变量或参数时,不会影响到外层函数中该变量的回收优化。即javascript引擎会排除FormalParameterList和所有VariableDeclaration表达式中的Identifier,再扫描所有Identifier来分析变量的可回收性。

总体结论

首先一个较为明确的结论是,以下内容会影响到闭包内变量的回收:

  • 嵌套的函数中是否有使用该变量。
  • 嵌套的函数中是否有直接调用eval。
  • 是否使用了with表达式。

Chakra、V8和SpiderMonkey将受以上因素的影响,表现出不尽相同又较为相似的回收策略,而JScript.dll和Carakan则完全没有这方面的优化,会完整保留整个LexicalEnvironment中的所有变量绑定,造成一定的内存消耗。

由于对闭包内变量有回收优化策略的Chakra、V8和SpiderMonkey引擎的行为较为相似,因此可以总结如下,当返回一个函数fn时:

  1. 如果fn的[[Scope]]是ObjectEnvironment(with表达式生成ObjectEnvironment,函数和catch表达式生成DeclarativeEnvironment),则:

    1. 如果是V8引擎,则退出全过程。
    2. 如果是SpiderMonkey,则处理该ObjectEnvironment的外层LexicalEnvironment。
  2. 获取当前LexicalEnvironment下的所有类型为Function的对象,对于每一个Function对象,分析其FunctionBody:

    1. 如果FunctionBody中含有直接调用eval,则退出全过程。
    2. 否则得到所有的Identifier。
    3. 对于每一个Identifier,设其为name,根据查找变量引用的规则,从LexicalEnvironment中找出名称为name的绑定binding。
    4. 对binding添加notSwap属性,其值为true。
  3. 检查当前LexicalEnvironment中的每一个变量绑定,如果该绑定有notSwap属性且值为true,则:

    1. 如果是V8引擎,删除该绑定。
    2. 如果是SpiderMonkey,将该绑定的值设为undefined,将删除notSwap属性。

    对于Chakra引擎,暂无法得知是按V8的模式还是按SpiderMonkey的模式进行。

从以上测试及结论来看,V8确实是一个优秀的javascript引擎,在这一方面的优化相当到位。而SpiderMonkey则采取一种更为友好的方式,不直接删除变量的绑定,而是将值赋为undefined,也许是SpiderMonkey团队考虑到有一些极端特殊的情况,依旧有可能导致使用到该变量,因此保证至少不会抛出ReferenceError打断代码的执行。而IE9的Chakra相比IE8的JScript.dll进步非常大,细节上的处理也很优秀。Opera的Carakan在这一方面则相对落后,完全没有对闭包内的变量回收进行优化,选择了最为稳妥但略显浪费的方式。

此外,所有带有优化策略的浏览器,都在内在开销和速度之间选择了一个平衡点,这也正是为什么“多个嵌套函数”这一测试用例中,虽然inner没有再使用largeObject对象,甚至在inner中的断点处,连help函数对象也已经解除绑定,却没有解除largeObject的绑定。基于这种现象,可以推测各引擎均只选择检查一层的关联性,即不去处理inner -> help -> largeObject这样深度的引用关系,只找inner -> largeObject和help -> largeObject并做一个合集来处理,以提高效率。也许这种方式依旧存在内存开销的浪费,但同时CPU资源也是非常贵重的,如何掌握这之间的平衡,便是javascript引擎的选择。

此外,根据部分开发者的测试,Chakra甚至有资格被称为现有最快速的javascript引擎,微软也一直在努力,而开发者更不应该一味地谩骂和嘲笑IE。
我们可以嘲笑IE6的落后,可以看不到低版本的IE曾经为互联网的发展做过的贡献,可以在这些历史产品已经没落的今天无情地给予打击,却最最不应该将整个IE系列一视同仁,挂上“垃圾”的名号。客观地去看待,去评价,正是一个技术人员应该具备的最基本的准则和素养。

JavaScript中消除闭包的一般方法介绍 JavaScript 的闭包是一个其主动发展的特性, 也是一个被动发展的特性. 也就是说, 一方面, JS 有了闭包能更好解决一些问题. 另一方面, JS 为了解决某些问题, 而不得不使用闭包勉强来解决问题. 前者这里不讨论, 如果 JS 闭包能更好的解决问题, 当然使用闭包更好. 我讨论的是后者, 是因为 JS 本身的限制, 而不得不磕磕绊绊地用闭包来解决的问题, 例如”变量只初始化一次”这样的需求. 常规的语言这样解决: 代码如下: class Class{  function init(){   this.n = 0;  }  function func(){   this.n ++; 立即下载

相关推荐

【OCCT】第3讲 OpenCasCade&VTK实现三维建模Demo

本文分享OpenCasCade&VTK共同实现三维建模Demo,希望对各位小伙伴有所帮助!1. 新建Visual Studio工程新建空项目添加main.cpp添加main函数2. 配置OpenCasCade & VTK 库配置包含路径:配置库文件:添加链接库:添加运行环境:注意:VTK库的版本要与编译OpenCasCade库时选择的版本一致,否则会出错!

qq_40041064的博客 779

python变量回收_Python变量的引用、拷贝和回收机制

1.Python中变量的引用Python中的变量都是指针,都是某个内存对象的引用。python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的...

weixin_39805387的博客 758

攻克+86手机号Discord验证墙:从“无效”到“成功”的实战指南

本文提供了一份针对+86手机号在Discord注册时频繁遭遇“手机号无效”问题的实战解决指南。文章系统分析了问题根源,并分步详解了从打造纯净网络环境、尝试多种手机号格式(如+86前加0),到更换iOS等客户端设备的有效方法,旨在帮助用户成功完成Discord手机号验证。

mac99的博客 1102

js中变量回收原则是什么?

综上所述,JavaScript中的变量回收原则主要基于标记清除和引用计数两种策略,并受到作用域和闭包等因素的影响。开发者需要了解这些原则并遵循最佳实践,以确保应用程序的内存使用得到有效管理。在JavaScript中,变量的回收主要遵循垃圾回收机制,这一机制自动管理内存,以减轻开发者的负担。

王铁柱666的博客 310

BPMN2.0规范及流程引擎选型方案

本文主要简明扼要的介绍了BPMN2.0规范的内容,可让读者快速度的了解BPMN2.0所涵盖的主要内容和图形样式。也较为详细的阐述了如何绘制标准的流程图,以及在软件层面中如何实现业务流程功能,和技术选型。

比特桃 1万+

全志T133-s3(Tina Linux)下RTL8723DS WiFi驱动移植与调试实战

本文详细介绍了在全志T133-s3平台(Tina Linux)上移植RTL8723DS WiFi驱动的完整流程,包括硬件连接、驱动源码获取、内核配置、系统适配、设备树配置以及常见问题排查。通过实战案例,帮助开发者快速解决SDIO接口通信、固件加载、电源管理等关键问题,实现稳定的WiFi功能。

weixin_30505225的博客 506

【js变量回收问题】

变量回收原则: 1.全局变量不会被回收 2.局部变量会被回收,也就是函数一旦运行完以后,函数内部的东西就会被销毁 3.只要被另外一个作用域所引用就不会被回收 例如: var i = 1; // 全局变量不会被回收 var i = 2; // 这里重复声明变量i,因此var声明被忽略,只是把i赋值为2 var add = function () { // 全局变量不会被回收 var i = 0; // 局部变量 return function () { i++; c

m0_53679993的博客 2077

海思3559av100平台lan9500模块调试记录

1. 前言 通过USB2.0接口扩展一路百兆虚拟网口 2. 配置lan9500驱动 make ARCH=arm64 menuconfig 开启LAN95XX驱动,编译进内核 保存内核配置 3. 编译内核 make ARCH=arm64 CROSS_COMPILE=aarch64-himix100-linux- uImage -j 20 cd ../../arm-trusted-firmware/arm-trusted-firmware ./mk.sh cp ...

jzwjzw19900922的博客 908

闭包中对变量的回收操作

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Doc

weixin_44666471的博客 623

YOLOv5 自定义模型 Android 部署完整指南

本文详细介绍了将YOLOv5模型部署到Android设备的完整流程,包含三个核心部分:首先验证官方模型测试,确保基础环境配置正确;随后进行模型转换,从PyTorch导出ONNX格式并优化,再转换为NCNN格式;最后在Android项目中集成自定义模型,包括文件替换、参数修改和代码适配。教程基于YOLOv5 6.1版本,使用NCNN框架进行移动端推理,涵盖了常见问题解决方案和关键配置要点,为开发者提供了从训练到部署的完整技术路线。

FJN110的博客 591

机加工机器人系列编程:Fanuc M-710iC_(2).FanucM-710iC机器人的硬件配置

Fanuc M-710iC 机器人是一种广泛应用在汽车零部件制造行业中的工业机器人。它的本体结构设计紧凑、稳定,适用于多种加工任务。了解机器人的本体结构是进行编程和维护的基础。

zhubeibei168的博客 990

python变量回收_python语法入门之变量、常量和垃圾回收机制

python语法入门之变量、常量和垃圾回收机制一、变量1.什么是变量​变量拆开看就是变化的量,量指的就是事物的状态,比如姓名,年龄,等级等等。2.为什么要有变量​ 为了让计算机能够像人一样去记忆事物的某种状态,并且状态是可以发生变化的 , 详细地说, 程序执行的本质就是一系列状态的变化,变是程序执行的直接体现,所以我们需要有一种机制能够反映或者说是保存下来程序执行时状态,以及状态的变化。3.怎么...

weixin_39702639的博客 356

VCAST创建单元测试工程

选择工作目录,后面创建胡UT工程将会生成到这个目录。

qq_42851449的博客 2480

JavaScript 关于闭包及变量回收问题

ㅤㅤㅤ ㅤㅤㅤ ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ(没有一种不幸可与失掉时间相比了。——屠格涅夫) ㅤㅤㅤ ㅤㅤㅤ ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ 问题的提出 假设有如下的代码: function outer() { var largeObject = LargeObject.fromSize('100MB'); return function() { console.log('inner'); }; } var inner = outer(); 在这一段代码中,o

Nodejs 986

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

js闭包变量回收问题

变量回收原则: 1.全局变量不会被回收 2.局部变量会被回收,也就是函数一旦运行完以后,函数内部的东西就会被销毁 3.只要被另外一个作用域所引用就不会被回收 两个实例: 一 function a(){   var b= 10;   return function(){     b++;     console.log(b);   } } a()(); //11 a()(); //11 分析: 在函数a中返回了一个匿名函数,在这个匿名函数中我们num++了一下,然后在函数外面执行了这个匿名函

莫问前程F1的博客 1410

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Go中被闭包捕获的变量何时会被回收

1. Go函数闭包Go语言原生提供了对闭包(closure)的支持。在Go语言中,闭包就是函数字面值[2]。Go规范中是这样诠释闭包的:函数字面值(function literals)是闭...

TonyBai 716

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

闭包、垃圾回收机制、闭包不被回收

闭包指在一个函数内部定义的函数,内部函数可以访问外部函数作用域中的变量,并且在外部函数执行完毕后仍然保持对这些变量的引用。换句话说,闭包可以捕获并存储其外部函数的局部变量,使得这些变量即使在外部函数执行完毕后仍然可以被内部函数访问和操作。

yajia2的博客 856

码农武:闭包和垃圾回收机制

闭包,作用域,垃圾回收,JavaScript垃圾回收

码农武的博客 1255

闭包的特性

官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。(函数就是一个表达式) JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。 什么是闭包:闭包是指在函数外部访问函数作用域中变量(局部变量)的函数;或者说闭包就是能够读取其他函数...

素描本里的男子的博客 1157

JavaScript闭包

在JavaScript开发中,闭包是一个非常重要且经常被提及的概念。它不仅可以帮助我们实现一些高级功能,还能解决一些常见的问题。本文将详细介绍闭包的概念、原理、应用场景以及如何正确使用和优化闭包。

前端小巷子的博客 690

闭包中的垃圾回收机制

闭包中的垃圾回收机制的原理和闭包保存内外部作用域的垃圾回收方面&lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8"&gt; &lt;title&gt;Document&lt;/title&gt; &lt;/head&gt; &lt;bo

Mr.ShyZhang趟过的前端“小路坑” 1731

js 闭包

  闭包,按我的理解就是把函数里的参数保存下来,一般情况一个函数(函数作用域)执行完毕,里面声明的变量会全部释放,被垃圾回收器回收。但闭包利用一个技巧,让作用域里面的变量,在函数执行完之后依旧保存没有被垃圾回收处理掉。  列如function show1(){ var a=1; return function(b){ return (a++)+b; } } co...

weixin_42453870的博客 204

关于闭包中变量的储存

//前言 闭包,这个概念对于每位JSer而言都不陌生,它几乎伴随着每个前端入门者的初学阶段,重要到几乎每家公司面试都会问。 关于闭包究竟是什么,闭包干嘛用的,网上各种回答也是五花八门,动不动就扯到隐匿变量/内存泄漏这些概念,让没有C基础的初学者越看越晕,我不能说那些是错的,不过显然对新手不太友好。曾几何时我也是被那些个故作高深的概念绕得七荤八素云里雾里,那今天这篇文章以一个简单到80岁老太都看得懂...

qq_41293573的博客 1955

【一文读懂】对闭包的理解及其衍生问题(作用域、垃圾回收、闭包的应用、释放闭包)

闭包可以说是前端必须要了解的内容,但面试时往往会问更多相关问题,比如我就碰到过这样的“组合技”:什么是闭包?什么是作用域链?写个闭包的例子吧!为什么形成了闭包?(面试官写了个例子)这样写是不是闭包?闭包涉及的变量,存储的时候是在栈内存吗?闭包有什么应用?防抖和节流的含义?写个防抖/节流函数吧!什么是垃圾回收?闭包为什么不会被回收?JS如何实现自动垃圾回收?如何手动进行垃圾回收?闭包会不会出现内存泄露?怎么避免内存泄露?怎么释放闭包?本文就将全面整理闭包及其衍生问题。

一个努力学习的程序猿 1706

闭包

闭包什么是闭包? 为什么要有闭包? 闭包基于的原理? 闭包的作用? 实现过程 ?

cz_sky的博客 1658
上一篇: 什么是“第一方Cookie”、“第三方Cookie”
下一篇: CSS语法简单入门
SleepInDelphi
博客等级 码龄19年 32粉丝 388原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值