JavaScript之闭包理解

闭包(Closure)是JavaScript学习过程中一个非常重要的问题

闭包和执行上下文和作用域链有着千丝万缕的关系。闭包是指有权访问另一个函数作用域的变量的函数(JavaScript高级程序设计(第三版)P178)

闭包是一个函数,对闭包的一个理解可以是所在的执行上下文已经出栈,但是仍然访问了其所在的执行上下文变量对象的函数

这里所指的所在的执行上下文指的是闭包函数对应的执行上下文,而不是闭包本省所对应的执行上下文

来一个简单的例子

function A(){var a = 2;function B(){console.log(a);}return B;
}
A()();

那么他的执行上下文栈行为是这样的

/*伪代码*/
// 代码执行时最先进入全局环境,全局上下文被创建并入栈
ECStack.push(globalContext);
// A 被调用,A 函数上下文被创建并入栈
ECStack.push(<A> functionContext);
// A 执行完毕,A 函数上下文出栈
ECStack.pop();
// B 被调用,B 函数上下文被创建并入栈
ECStack.push(<B> functionContext);
// B 执行完毕,B 函数上下文出栈
ECStack.pop();
// 代码执行完毕,全局上下文出栈
ECStack.pop();

我们都知道,JavaScript 拥有自动的垃圾回收机制,当一个值失去引用的时候,垃圾回收机制会根据特殊的算法找到它并将其回收。

函数的执行上下文在出栈后,其变量对象会失去引用等待被回收,而闭包的存在会阻止这一过程,因为闭包的作用域链包含了其所在执行上下文的变量对象。

通过上面的代码可以看出,在B函数执行的时候,A的上下文已经出栈了,按照JavaScript的垃圾回收机制,A上下文的变量对象失去引用后会被垃圾回收机制回收,但是由于B上下文作用域链包含了A上下文的变量对象,所以A上下文的变量对象不会被垃圾回收机制回收。

我们知道函数作用域是在函数被定义(声明)的时候确定的。每一个函数都会包含一个[[scope]]内部属性,在函数被定义的时候,该函数的[[scope]]属性会保存其上层上下文的变量对象,形成包含上层上下文变量对象的层级链。

那么刚刚的代码上下文应该是这样的,在创建的时候

B.[[scope]]=[AContext.VO,globalContext.VO]

在B被调用的时候,其执行上下文会被创建并入栈,此时会生成变量对象并将该变量对象添加进作用域链的顶端,并将[[scope]]添加进作用域链

BContext.Scope = [BContext.VO].concat(B.[[scope]])
=>
BContext.Scope = [BContext.VO,AContext.VO,globalContext.VO]

可见,B上下文的作用域链包含了A上下文的变量对象,并且由于B访问A中的变量,阻止了A上下文的变量对象被垃圾回收机制回收。

看一个面试题经常会遇到的一个关于闭包的很经典的题目

var arr = [];
for (var i = 0; i < 3; i++) {arr[i] = function () {console.log(i);};
}arr[0]();//3
arr[1]();//3
arr[2]();//3

在 arr[0] 函数执行之前,我们可以知道,全局上下文的变量对象如下所示

globalContext = {VO:{arr:[],i=3}
}

在 arr[0] 被调用执行时,其作用域链在函数上下文的创建阶段被创建,其作用域链如下

arr[0]Context = {Scope: [arr[0]Context.VO, globalContext.VO]
}

arr[0]函数会在自身变量对象中寻找i(arr总没有i),所以会向上找,找到全局上下文变量对象中的i,所以输出3

那么如何解决闭包

立即执行函数

var arr =  [];
for(var i = 0; i < 3; i++){arr[i] =  (function(j) {return function(){console.log(j);}})(i)
}
arr[0]();//0
arr[1]();//1
arr[2]();//2

ES6中的let

var arr = [];
for (let i = 0; i < 3; i++) {arr[i] = function () {console.log(i);};
}arr[0]();//0
arr[1]();//1
arr[2]();//2

setTimeout

也还可以利用setTimeout的第三个参数

    var arr = [];for(var i = 0; i < 3; i++){arr[i] = setTimeout(function(i){console.log(i);},0,i)}

JavaScript之闭包理解相关推荐

  1. javascript之闭包理解以及应用场景

    1 function fn(){2 var a = 0;3 return function (){4 return ++a;5 } 6 } 如上所示,上面第一个return返回的就是一个闭包,那么本质 ...

  2. 深入理解javascript的闭包

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...

  3. 深入理解JavaScript的闭包特性如何给循环中的对象添加事件

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  4. 【Javascript】深入理解this作用域问题以及new/let/var/const对this作用域的影响

    理解this作用域 <javascript高级程序设计>中有说到: this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象调用时,t ...

  5. JavaScript之全面理解面向对象的JS

    今天看到一篇文章写得很好,对于像博主这种js一般级别的菜鸟很有帮助,博主秉着"好文要转"的原则收藏了这篇文章,简单排了下版,分享给大家,本文转自原文:http://www.ibm. ...

  6. mysql闭包的概念_彻底搞懂JavaScript的闭包、防抖跟节流

    最近出去面试了一下,收获颇多!!! 以前的我,追求实际,比较追求实用价值,然而最近面试,传说中的面试造火箭,工作拧螺丝,竟然被我遇到了.虽然很多知识点在实际工作中并不经常用到,但人家就是靠这个来筛选人 ...

  7. javascript之异步操作理解---回调函数,async,await以及promise对象

    javascript之异步操作理解---回调函数,async,await以及promise对象 概述 概述 写在前面:虽然平时做项目,但是发现自己写的代码还是很烂.最近接触了一个对性能要求比较高的项目 ...

  8. 【javascript】深入理解对象

    为什么80%的码农都做不了架构师?>>>    今天学习的主题是 JavaScript对象. 要创建一个JavaScript对象大家应该都觉得很简单,直接写上一行 var obj = ...

  9. 我对javascript对象的理解

    前言 JavaScript这门语言除了基本类型都是对象,可以说JavaScript核心就是对象,因此理解JavaScript对象及其种种特性至关重要,这是内功.本文介绍了我对es5对象,原型, 原型链 ...

  10. Javascript的闭包及其使用技巧实例

    Javascript的闭包及其使用技巧实例 一.闭包的基本概念 闭包(Closure)是一个引用了自由变量的函数,记录了该函数在定义时的scope chain.又称词法闭包(Lexical Closu ...

最新文章

  1. pytorch 图像归一化
  2. 获山东科技最高奖-农业大健康·万书波:沉醉谋定花生增产
  3. 唐岩自述奋斗史:从娄底青年到陌陌上市
  4. 百练4103:踩方格
  5. Android官方开发文档Training系列课程中文版:Android的安全建议
  6. java王大拿谢大脚_《乡村爱情1》:“王大拿”赵本山有3大亮点,追谢大脚根本不算啥...
  7. canvas笔记-画一个五角星(含算法)
  8. [转载]Validation of viewstate MAC failed异常的原因及解决方法
  9. 不止命令行-自定义VS生成事件
  10. 【python】装饰器的练习题
  11. git rebase -i之我见
  12. java程序编译后会产生_java程序编译后会产生什么
  13. css 设置浏览器最小宽度
  14. Cknife(中国菜刀) and AntSword(中国蚁剑)使用
  15. 机器学习之初识SVM
  16. html生日祝福心形,心形生日祝福QQ空间个性留言代码_送你的
  17. SwiftUI SF Symbols 好处及其使用指南
  18. 流利说英语level4_英语流利说懂你英语 Level4 Unit1 Part1 Vocabulary
  19. 安利几个实用且有趣的Excel实用技巧给你
  20. 【SEED Labs 2.0】ARP Cache Poisoning Attack Lab

热门文章

  1. 全渠道数字化营销平台
  2. 【盘点】imx6的应用
  3. 内外盘分仓跟单系统源码CTP程序化交易系统源码
  4. 计算机知识竞赛形式,关于计算机知识竞赛试题
  5. 计算机知识竞赛的策划案,计算机趣味知识竞赛活动策划书
  6. linux 安装触摸版驱动程序,在ubuntu和linux上配置触摸屏驱动程序启用触摸屏
  7. 谷歌地图开放俄军事设施高分辨率卫星图
  8. STM32 ADC 过采样技术
  9. 2022 数学建模B题 高教社杯 含半成品论文 部分代码 全部数学模型 和全套思路
  10. javassist 学习笔记