对JavaScript中闭包的理解

相信很多人都有看过关于闭包的文章,但是真正意义上的了解清楚的也不多,今天我们就来谈谈对闭包的理解。

闭包在JavaScript中一直是一个很重要的存在,闭包很重要但是又很难理解,起初我也是这样认为,但只要真的清楚之后,你会觉得很有趣。

我们先来看一个闭包的例子:

1 function foo() {
2  let a = 2;
3  function bar() {
4   console.log(a);
5  }
6  return bar;
7 }
8 let baz = foo();
9 baz();

大家肯定都写过类似的代码,相信很多小伙伴也知道这段代码应用了闭包,但是,为什么会产生闭包,闭包又是在哪里?

回答上面的问题,首先必须先知道闭包是什么,才能分析出闭包为什么产生和闭包到底在哪?

当一个函数能够记住并访问到其所在的词法作用域及作用域链,特别强调是在其定义的作用域外进行的访问,此时该函数和其上层执行上下文共同构成闭包。

需要明确几点:

  1、闭包一定是函数对象

  2、闭包和词法作用域,作用域链,垃圾回收机制息息相关

  3、当函数一定是在其定义的作用域外进行的访问时,才产生闭包

  4、闭包是由该函数和其上层执行上下文共同构成

闭包是什么,我们说清楚了,下面我们看下闭包是如何产生的。

现在我假设JS引擎执行到这行代码:

let baz = foo();

  

此时,JS的作用域是这样的:

这个时候foo函数已经执行完,JS的垃圾回收机制应该会自动将其标记为"离开环境",等待回收机制下次执行,将其内存进行释放(标记清除)。

但是,我们仔细看图中粉色的箭头,我们将bar的引用指向baz,正是这种引用赋值,阻止了垃圾回收机制将foo进行回收,从而导致bar的整条作用域链都被保存下来。

接下来,baz()执行,bar进入执行栈,闭包(foo)形成,此时bar中依旧可以访问到其父作用域气泡中的变量a。

这样说可能不是很清晰,接下来我们借助chrome的调试工具看下闭包产生的过程。

当JS引擎执行到这行代码let baz = foo();时:

图中所示,let baz = foo();已经执行完,即将执行baz();,此时Call Stack中只有全局上下文。

接下来baz();执行:

我们可以看到,此时bar进入Call Stack中,并且Closure(foo)形成。

针对上面我提到的几点进行下说明:

  1、上述第二点(闭包和词法作用域,作用域链,垃圾回收机制息息相关)大家应该都清楚了

  2、上述第三点,当函数baz执行时,闭包才生成

  3、上述第四点,闭包是foo,并不是bar,很多书(《you dont know JavaScript》《JavaScript高级程序设计》)中,都强调保存下来的引用,即上例中的bar是闭包,而chrome认为被保存下来的封闭空间foo是闭包

仔细想来,在我们作用域模型中,作用域链让我们的内部bar气泡能够"看到"外面的世界,而闭包则让我们的外部作用域能够"关注到"内部的情况成为可能。可见,只要我们愿意,内心世界和外面世界是可以相通的。

使用闭包时的注意事项:

闭包,在JS中绝对是一个高贵的存在,它让很多不可能实现的代码成为可能,但是物虽好,也要合理使用,不然不但不能达到我们想要的效果,有的时候可能还会适得其反。

内存泄漏(Memory Leak)

JavaScript分配给Web浏览器的可用内存数量通常比分配给桌面应用程序的少,这样做主要是防止JavaScript的网页耗尽全部系统内存而导致系统崩溃。

因此,要想使页面具有更好的性能,就必须确保页面占用最少的内存资源,也就是说,我们应该保证执行代码只保存有用的数据,一旦数据不再有用,我们就应该让垃圾回收机制对其进行回收,释放内存。

我们现在都知道了闭包阻止了垃圾回收机制对变量进行回收,因此变量会永远存在内存中,即使当变量不再被使用时,这样会造成内存泄漏,会严重影响页面的性能。因此当变量对象不再适用时,我们要将其释放。

我们拿上面代码举例:

function foo() {
 let a = 2;
 function bar() {
   console.log(a);
 }
 return bar;
}
let baz = foo();
baz();//baz指向的对象会永远存在堆内存中
baz = null;//如果baz不在使用,将其指向的对象释放

原文地址:https://www.cnblogs.com/qingxiajun/p/8970464.html

时间: 2024-10-25 09:00:56

对JavaScript中闭包的理解的相关文章

第二话:javascript中闭包的理解

闭包是什么? 通过闭包,子函数得以访问父函数的上下文环境,即使父函数已经结束执行. OK,我来简单叙述下,先上图. 都知道函数是javascript整个世界,对象是函数,方法是函数,并且js中实质性的面向对象相关也都是函数来实现和延伸,例如:"类". window:是指js中window类,也是js最高一层,因为什么这么说,因为你所有创建的方法和属性其实都在window之内.window中的所有方法,在自己创建的方法中都可以调到.可以仔细想想alert,在任何地方都可以alert,其实

javascript中闭包的原理与用法小结(转)

一.在javaScript中闭包的五种表现形式如下: 1 /** 2 * Created by admin on 2016/12/26. 3 *//* 4 //向函数对象添加属性 5 function Circle(r){ 6 this.r=r; 7 } 8 Circle.prototype.PI=3.1415926; 9 Circle.prototype.area=function(){ 10 return this.PI*this.r*this.r; 11 }; 12 var c=new C

Javascript中Function declarations 理解

首先来看一段代码: 1.f = function() {return true;}; 2.g = function() {return false;}; 3.(function() { 4. if (g() && [] == ![]) { 5. f = function f() {return false;}; 6. function g() {return true;} 7. } 8.})(); 9.console.log(f()); 理解上面这段code有几个关键点: 第4行code的

javascript中闭包最简单的简绍

javascript中闭包是什么 JavaScript 变量可以是局部变量或全局变量.私有变量可以用到闭包.闭包就是将函数内部和函数外部连接起来的一座桥梁. 函数的闭包使用场景:比如我们想要一个函数来执行计数功能. 如果设计全局变量 1 var counter=0; 2 function add(){ 3 4 return counter++;} // add(); 在浏览器调用 add();//值为2 问题是如何当我们设计另外一个方法时用到需要counter这个变量,我们在进行修改无疑会改变c

JavaScript中闭包之浅析解读

JavaScript中的闭包真心是一个老生常谈的问题了,最近面试也是一直问到,我自己的表述能力又不能完全支撑起来,真是抓狂.在回来的路上,我突然想到了一个很简单的事情,其实我们在做项目时候,其实就经常用到闭包的,可是面试问的时候,回答又往往是我们经常搜到的答案,唉 不管是应付面试 还是真的想学点东西 ,我也用自己的理解跟大家分享一下,书面化就避免不了了的. 1.闭包是什么? 红宝书中曰:“是指有权访问另外一个函数作用域中的变量的函数.” 简单的说,JavaScript允许使用内部函数---即函数

javascript中闭包的工作原理

一.什么是闭包? 官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.相信很少有人能直接看懂这句话,因为他描述的太学术.其实这句话通俗的来说就是:JavaScript中所有的function都是一个闭包.不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”.看下面这段代码: 1 2 3 4 5 6 7 function a() { var i = 0; function b() { ale

Javascript 中闭包的概念

一直再说闭包闭包,其实自己一直不懂闭包是个什么意思,今天,上百度找了找闭包的相关资料,参考整理了下,希望以后能用得着: 闭包其实是javascript语言中的一个难点,也是该语言的一个特色,据说很多高级应用都需要闭包的支持: 先理解下下面的几个概念: 1.变量的作用域 javascript中声明变量使用var 关键字,稍微了解的同学都知道,加了var关键字声明的变量是局部变量,反之则为局部变量 例如: var text = 'hello';   局部变量 text = 'world'; 全局变量

Javascript中 闭包问题

学习Javascript闭包(Closure)闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.下面就是我的学习笔记,对于Javascript初学者应该是很有用的.一.变量的作用域要理解闭包,首先必须理解Javascript特殊的变量作用域.变量的作用域无非就是两种:全局变量和局部变量.Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. var n=999; function f1(){ alert(n); } f1()

Javascript中闭包问题(转载)

学习Javascript闭包(Closure) 作者: 阮一峰 日期: 2009年8月30日 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 下面就是我的学习笔记,对于Javascript初学者应该是很有用的. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. var n=999; fu