博客
关于我
JavaScript闭包(一)——实现
阅读量:443 次
发布时间:2019-03-06

本文共 2547 字,大约阅读时间需要 8 分钟。

闭包的官方的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

通俗点的说法是:

  1. 从理论角度:所有的函数。因为它们都在创建的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域。

  2. 从实践角度:以下函数才算是闭包:

            即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)
            在代码中引用了自由变量(自由变量:是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量)
function testFreedom() {            var freedomVar = 1;            function inner(param) {                echo(pclosure1, param + freedomVar);//将结果打印到pclosure1中            }          return inner;        }

对于inner函数来说,freedomVar就属于自由变量。

 

一、一个实现

     function echo(p, html) {            p.innerHTML += html + '
'; }     function closure() { var innerVar = 0; function inner() { return ++innerVar; } return inner; } var quote = closure(); echo(pclosure1, quote());//1 echo(pclosure1, quote());//2

先看看结果情况:

1、第一次quote函数的结果为1,第二次为2

2、inner嵌套在函数closure内部;函数closure返回函数inner

3、结合上面的闭包实践角度特点,可以得出closure是一个闭包

4、函数closure在返回后不会被GC回收,原因如下:

  1. closure返回函数inner的引用给quote

  2. 函数inner的作用域链包含了对函数closure的活动对象(activation_1)的引用,如下图所示。

  3. inner可以访问到closure中定义的所有变量和函数

  4. 函数inner被quote引用

  5. 函数inner又依赖函数closure

 

二、大致的作用域图

 

三、closure里面的大致执行步骤

1) 初始化Global Object即window对象,Variable Object(全局执行环境中的可变对象)为window对象本身。创建Scope Chain对象,假设为scope_1,其中只包含window对象

2) 扫描JavaScript源代码,从结果中可以得到定义的变量名、函数对象。按照扫描顺序:

  1. 发现函数closure的定义,使用这个定义创建函数对象,传给创建过程的Scope Chain为scope_1。将结果添加到window的属性中,名字为closure,值为返回的函数对象

  2. 发现变量quote,在window对象上添加quote属性,值为undefined

3) 执行函数closure,得到返回值:

  3.1 创建Activation Object,假设为activation_1;创建一个新的Scope Chain,假设为scope_2,scope_2中第一个对象为activation_1,第二个对象为window对象

  3.2 处理参数列表。创建arguments对象并进行设置,将arguments设置为activation_1的属性

  3.3 对closure的函数体执行类似步骤2的处理过程:

  1. 发现变量innerVar,在activation_1对象上添加innerVar属性,值为undefined

  2. 发现函数inner的定义,使用这个定义创建函数对象,传给创建过程的Scope Chain为scope_2(函数closure的Scope Chain)。将结果添加到activation_1的属性中,名字为inner,值为返回的函数对象。inner的内部 [[Scope]]就是scope_2

  3.4 执行innerVar赋值语句,赋值为"0"

  3.5 执行inner

  1. 创建Activation Object,假设为activation_2;创建一个新的Scope Chain,假设为scope_3,scope_3中第一个对象为activation_2,接下来的对象依次为activation_1、window 对象(取自fn2的[[Scope]],即scope_2)

  2. 处理参数列表。因为inner没有参数,所以只用创建arguments对象并设置为activation_2的属性

  3. 对inner的函数体执行类似步骤2的处理过程,没有发现变量定义和函数声明

  4. 执行函数体。对任何一个变量引用,从scope_3上进行搜索,这个示例中,innerVar将在activation_1上找到

  5. 返回inner的返回值

  3.6 返回结果

4) 打印结果

 

 

 

demo下载:

 

参考资料:

JavaScript闭包其一:闭包概论

JavaScript闭包其二:闭包的实现

JavaScript闭包其三:闭包的用法

简单易懂的JavaScript闭解

Javascript 闭包

Javascript闭包——懂不懂由你,反正我是懂了

理解Javascript的闭包

深入理解Javascript闭包(closure)

动态作用域和词法域的区别是什么?

  ECMAScript5浏览器兼容表

我们应该如何去了解JavaScript引擎的工作原理

JavaScript 中的函数式编程实践

理解Javascript_13_执行模型详解

转载地址:http://djafz.baihongyu.com/

你可能感兴趣的文章
最通俗易懂的囚徒困境
查看>>
MySQL 1064 You have an error in your SQL syntax 错误解决办法
查看>>
liteide错误: 进程无法启动--解决方法
查看>>
Java程序中的代理作用和应用场景及实现
查看>>
Java 前台后台数据传递、中文乱码解决方法
查看>>
Git报错:Permission denied (publickey)
查看>>
常见的图文布局
查看>>
Laravel - 上手实现 - 文件上传、保存到 public 目录下
查看>>
将mongo设置为windows的服务
查看>>
【Flink】Flink 底层RPC框架分析
查看>>
【集合框架】JDK1.8源码分析之LinkedList(七)
查看>>
Jenkins 集成postman 自动化运行接口测试用例
查看>>
django+appium实现UI自动化测试平台(开源部分,可定制开发)
查看>>
第七届C/C++B-方格填数 DFS
查看>>
数据结构课设--3哈夫曼编码译码系统(树应用)
查看>>
pku 1061 青蛙的约会 扩展欧几里得
查看>>
Spring Boot 2.4 配置文件将加载机制大变化
查看>>
也来玩玩 javascript对象深拷贝,浅拷贝
查看>>
【转载】Kubernetes CNI网络最强对比:Flannel、Calico、Canal和Weave
查看>>
Kubernetes实战总结 - 动态存储管理StorageClass
查看>>