什么是闭包?

简单理解,当在一个函数的外部访问函数内部定义的变量的时候就会形成一个闭包,由这个理解可以知道,当一个函数执行完成的时候,一般情况下,其作用域会被销毁,其内部定义的变量也会变得不可访问,所以闭包打破了这个现象。闭包造成一个函数执行完成之后,其创建的作用域不会被销毁,因为它被函数外部的对象或者变量所引用。由此可知,闭包可以实现作用域的延时存在,但这也会造成内存的泄露。所以在明确知道自己需要使用闭包的时候,采取使用闭包,否则就不要使用闭包。

Eg:

function demo(){

var internal=10;

return function (){

alert(internal);

};

}

demo()();

以上的代码执行之后会弹窗显示10.我们在demo方法的外部打印了其内部的变量,这个就是闭包。

  1. 作用域产生的原理

我们知道,当执行一个函数的时候,其访问变量的顺序是,首先在其自己的作用域上查询,如果查询不到,则会往其上层作用域来查询,一直查询到最终根作用域(也就是window对象),如果还是查询不到,则会抛出一个undefined的错误。

那么作用域是如何产生的呢?

首先在执行js代码之前,会产生一个全局作用域GO,也就是window对象(后面不再说明),而对于一个函数执行之前会创建自己的作用域AO,并持有其上层函数的作用域,以形成一个作用域链。

作用域创建的基本步骤:

1、  创建一个AO,并持有上层函数的作用域

2、  初始化形参和内部声明的变量(变量声明的提升),并初始化为undefined

3、  将形参和实参相统一

4、  函数定义整体提升

以一下代码为例

function a(){

var a1=0;

function b(){

var b1=1;

function c(){

var c=2;

}

c();

}

b();

}

a();

当js执行之前会创建一个GO

GO{

a:function()…

}

执行a函数的时候会创建a函数的作用域AO

a_AO{

AO_chain:GO,

a1:0,

b:function()…

}

由以上定义可知

b的AO为

b_AO{

AO_Chain:a_AO,

b1:1,

c:function()…

}

c的作用域与此类似,由于此处重点是为了根据作用域来解释闭包的原因,所以这里不再详细的说明作用域,如不了解请自行百度。

  1. 闭包

eg:有如下一个函数

function demo(){

var arr=[];

for(var i=0;i<10;i++){

arr[i]=function(){

document.write(i+ “ ”);

}

}

return arr;

}

var arr=demo();

for(var j=0;j<10;j++){

arr[j]();

}

熟悉闭包的人都知道最后打印的结果是10个10

10 10 10 10 10 10 10 10 10 10

大家知道这是由于闭包对变量的持有造成的,那么根据作用域的原理是怎么产生的呢?

  1. GO

GO{

arr = undefined,

demo = function()…

}

  1. demo 的AO

d_AO{

ao_chain:GO,

arr=[],//用于存放10个函数

i=0

}

  1. 当执行完成 arr=demo[]之后;

d_AO{

ao_chain:GO,

arr=[function()…,function()…{}],//10个函数,每个函数都是//function(){document.write(i + ‘ ’)}

i=10

}

  1. 执行arr数组中的函数的时候

a_AO{

ao_chain:d_AO

}

从上面的作用域链可以知道,当数组的函数想要访问i变量的时候,发现它自己的作用域中没有这个变量,所用会通过其作用域链进行查询,然后在d_AO中找到了i对象,此时i对象的值变为了10,所以arr数组中的所有的函数最后打印的结果都是一样的。

为了解决这个问题,可以使用立即执行函数

如下

function demo(){

var arr=[];

for(var i=0;i<10;i++){

(function(j){arr[j]=function(){

document.write(j+ “ ”);

}})(i);

}

return arr;

}

var arr=demo();

for(var j=0;j<10;j++){

arr[j]();

}

结果如图

0 1 2 3 4 5 6 7 8 9

从作用域的解释来看(如果对立即执行函数不了解的,请百度查阅立即执行函数的相关内容)

  1. GO

GO{

arr = undefined,

demo = function()…

}

  1. demo 的AO

d_AO{

ao_chain:GO,

arr=[],//用于存放10个函数

i=0

}

前两步与上面的方法创建的作用域相同

第3步开始有些差异

  1. 执行demo函数的时候

在执行demo函数的时候,因为内部存在一个立即执行函数,所以这个匿名函数会被立即执行,它也会创建自己的作用域

n_AO{

ao_chain:d_AO,

j:n//这里的n保存的是i的当前值,例如第一个n对应的为j:0

}

//对应的arr[j]=function(){document.write(j+ “ ”);},j不会被替换,仍然是保持引用

  1. 执行arr函数的时候

arr_AO{

ao_chain:n_AO//例如arr[1]对应的就是ao_chain:1_AO

}

从上面的作用域链可以看出,当执行arr中的函数的时候,例如执行arr[2]的时候,首先到自己的作用域查询j变量,发现找不到j,于是沿着作用域链进行查找,首先查询2_AO,在2_AO中找到了j变量,此时j变量的值为2,于是打印的结果就为2,这样我们就实现了我们得需要。

以上解释若有错误,还望指点,包涵。谢谢!

JS闭包作用域解析的更多相关文章

  1. js闭包的作用域以及闭包案列的介绍:

    转载▼ 标签: it   js闭包的作用域以及闭包案列的介绍:   首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...

  2. 大部分人都会做错的经典JS闭包面试题

    由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...

  3. Js闭包常见三种用法

        Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...

  4. js闭包之初步理解( JavaScript closure)

    闭包一直是js中一个比较难于理解的东西,而平时用途又非常多,因此不得不对闭包进行必要的理解,现在来说说我对js闭包的理解. 要理解闭包,肯定是要先了解js的一个重要特性, 回想一下,那就是函数作用域, ...

  5. (原创)JS闭包看代码理解

    <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...

  6. js闭包理解

    js闭包的作用是使函数外可以访问函数内部的变量,是通过 在函数内部 定义 访问函数内变量 的函数实现的,内部的一个函数产生一个闭包 function a() { var i=0; return fun ...

  7. js闭包理解实例小结

    Js闭包 闭包前要了解的知识  1. 函数作用域 (1).Js语言特殊之处在于函数内部可以直接读取全局变量 <script type="text/javascript"> ...

  8. Js闭包的用途

    本来想总结一点JavaScript中的闭包的一些用法,在查资料的时候发现了一篇很好的文章,就转过来收藏了,下面附上传送门: js闭包的用途 ---------sunlylorn 我们来看看闭包的用途. ...

  9. js闭包和ie内存泄露原理

    也议 js闭包和ie内存泄露原理 可以, 但小心使用. 闭包也许是 JS 中最有用的特性了. 有一份比较好的介绍闭包原理的文档. 有一点需要牢记, 闭包保留了一个指向它封闭作用域的指针, 所以, 在给 ...

随机推荐

  1. kettle web化

    kettle web化 通过Java API调用kettle核心代码,并基于Spring Boot提供简易的Web管理界面. 背景 在工作中,通过kettle这款ETL产品进行数据处理时,是通过kit ...

  2. Java 设计模式(概述)

    设计模式的三个分类                                                                                   创建型模式:对象 ...

  3. Python基础之模块+异常

    一.模块相关概念 1.定义:包含一系列数据.函数.类的文件,通常以.py结尾. 2.作用:让一些相关的数据,函数,类有逻辑的组织在一起,使逻辑结构更加清晰.有利于多人合作开发. 3.模块导入方式(三种 ...

  4. javabean简介

    Javabean简介 JavaBean是一个可重复使用的软件组件.实际上JavaBean是一种Java类,通过封装属性和方法成为具有某种功能或者处理某个业务的对象,简称bean.由于javabean是 ...

  5. SQA计划和验收测试规程设计

    一.SQA(软件质量保证)的定义 软件质量保证(SQA-Software Quality Assurance)是建立一套有计划,有系统的方法,来向管理层保证拟定出的标准.步骤.实践和方法能够正确地被所 ...

  6. C#单元测试,带你快速入门

    注:本文示例环境 VS2017 XUnit 2.2.0 单元测试框架 xunit.runner.visualstudio 2.2.0 测试运行工具 Moq 4.7.10 模拟框架 为什么要编写单元测试 ...

  7. 流媒体协议(二):RTMP协议

    一.概念与摘要 RTMP协议从属于应用层,被设计用来在适合的传输协议(如TCP)上复用和打包多媒体传输流(如音频.视频和互动内容).RTMP提供了一套全双工的可靠的多路复用消息服务,类似于TCP协议[ ...

  8. Eclipse显示行号

    Windows->preference->General->Editors->Text Editors->Show line numbers

  9. [Swift]LeetCode882. 细分图中的可到达结点 | Reachable Nodes In Subdivided Graph

    Starting with an undirected graph (the "original graph") with nodes from 0 to N-1, subdivi ...

  10. http初探

    http超文本传输协议 一.版本差异: 版本分0.9   1.0   1.1    2.0 http0.9/1.0已经过时:目前主要是1.1版本的,2.0版本的还没普及. http1.1 ----在同 ...