浅析js闭包
闭包是一个老生常谈的问题,简单概括下闭包的形成的两个条件:
1、定义在函数内部
2、函数内部引用父层作用域变量
举一个最简单的例子:
function test() {
var a = 1;
function hello() {
console.log(a);
}
return hello;
}
var world = test();
world(); //
以上代码会在控制台输出“1”。这是什么为什么呢?函数内部变量在调用结束后一般都会销毁,以上代码在test方法调用结束后并没有被销毁,这是由于js语言本身垃圾回收导致的。众所周知,js的垃圾回收机制是引用计数,当变量在其他作用域被引用时,该变量就不会被销毁,会一直存在内存中,这样就形成了闭包。在调试代码的过程中也可以在开发者工具中看出,如下图所示:

以上可以看出,当前环境存在一个作用域,Closure(text),包含引用父层的作用域的变量a。
js函数参数传递分为数值传递和引用传递,数值传递针对参数的类型为number/string/boolean....;引用传递针对参数类型为object/array....;所以在针对引用父层参数时,要注意父层参数类型,如果为数值传递,父层参数改变并不会影响闭包执行结果,但是如果参数是引用传递,要注意闭包里的参数引用的是父层变量地址,变量发生改变,闭包的执行结果会随之改变,以下代码可以看出:
var obj = {
num: {
b: 1
}
}
function test(obj) {
var a = obj.num;
function hello() {
console.log(a.b);
}
return hello;
}
var world = test(obj);
world(); //
obj.num.b = 2;
test(obj);
world(); //
执行结果:
再说一个经典的面试题:
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
想必大家都知道这段代码的执行结果是5个1,但是有没有想过为什么会是5个1呢?
setTimeout函数比较特殊,其执行优先级要低于for循环,循环结束后才会被执行,其匿名函数类似于一个回调,匿名函数都引用了变量i,var声明的变量又不存在块级作用域,最终循环结束后,i值变为5,在回调执行过程中,会向父层作用域执行RHS查询(就是查找变量i的值是否存在),i的值目前存在于全局变量window中,但是已变成了5,所以会输出5个5。

如何让其一次性输入0,1,2,3,4呢?
其实问题的本源在于js语言中本来不存在块级作用域,for循环声明的变量i最终是在全局变量中,每次循环都会更新一次全局变量中的值,所以实现块级作用域有两种常用的方法,一是借助es6的声明变量的方法let,第二个是利用闭包;
闭包的代码如下:
for (var i = 0; i < 5; i++) {
setTimeout((function(i) {
console.log(i);
})(i), 0)
}
正如文章刚开始所述,setTimeout回调中引用的是父层函数中变量i的值,在每次声明的时候,都会将当前的i值传递给闭包,其有自己单独的作用域,不再是引用同一变量,具体作用域情况如下所示:

以上仅为个人看法,如有错误,烦请指出,谢谢!
浅析js闭包的更多相关文章
- js闭包的作用域以及闭包案列的介绍:
转载▼ 标签: it js闭包的作用域以及闭包案列的介绍: 首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...
- 大部分人都会做错的经典JS闭包面试题
由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...
- 浅析JS中的模块规范(CommonJS,AMD,CMD)////////////////////////zzzzzz
浅析JS中的模块规范(CommonJS,AMD,CMD) 如果你听过js模块化这个东西,那么你就应该听过或CommonJS或AMD甚至是CMD这些规范咯,我也听过,但之前也真的是听听而已. ...
- Js闭包常见三种用法
Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...
- js闭包之初步理解( JavaScript closure)
闭包一直是js中一个比较难于理解的东西,而平时用途又非常多,因此不得不对闭包进行必要的理解,现在来说说我对js闭包的理解. 要理解闭包,肯定是要先了解js的一个重要特性, 回想一下,那就是函数作用域, ...
- (原创)JS闭包看代码理解
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...
- js闭包理解
js闭包的作用是使函数外可以访问函数内部的变量,是通过 在函数内部 定义 访问函数内变量 的函数实现的,内部的一个函数产生一个闭包 function a() { var i=0; return fun ...
- js闭包理解实例小结
Js闭包 闭包前要了解的知识 1. 函数作用域 (1).Js语言特殊之处在于函数内部可以直接读取全局变量 <script type="text/javascript"> ...
- Js闭包的用途
本来想总结一点JavaScript中的闭包的一些用法,在查资料的时候发现了一篇很好的文章,就转过来收藏了,下面附上传送门: js闭包的用途 ---------sunlylorn 我们来看看闭包的用途. ...
随机推荐
- css 选择器/table属性/type 属性
css style样式---要写单位px style=" width: 200px; height :300px;" ;是结束符
- AD9361框图
1. Fir滤波器的阶数为64或128 而内插或抽取因子为:1.2或4. HB1和HB2的内插或抽取因子为1或2而HB3的因子为1.2或3 BB_LPF为:三阶巴特沃斯低通滤波器,3dB点频率可编程, ...
- 中介模型以及优化查询以及CBV模式
一.中介模型:多对多添加的时候用到中介模型 自己创建的第三张表就属于是中介模型 class Article(models.Model): ''' 文章表 ''' title = models.Char ...
- kafka 的安装部署
Kafka 的简介: Kafka 是一款分布式消息发布和订阅系统,具有高性能.高吞吐量的特点而被广泛应用与大数据传输场景.它是由 LinkedIn 公司开发,使用 Scala 语言编写,之后成为 Ap ...
- 【mongo】可以用localhost启动,无法用ip启动问题的解决
问题: mongo安装在a.b.c.d机器上,启动mongo服务后, mongo localhost:27017可以进入数据库, mongo 127.0.0.1:27017也可以进入数据库 mongo ...
- Python基础之关于表达式
初识表达式: 优雅.清晰和务实是python的核心价值观,如果想通过操作和处理一个序列(或其他的可迭代对象)来创建一个新 的列表时可以使用列表解析(List comprehensions)和生成表达式 ...
- 步步为营-104-SQL语句(截取字符串)
按照指定字符截取字符串,截取出300 业务需求:想比对图片中框线部分是否一致 第一步 从最后一个/截取到末尾 select top 1 reverse(substring(reverse(Proces ...
- Python零基础入门之Tkinter的对话框
这篇博客主要是总结一下Tkinter中的对话框的使用,值得一提的是自从python3.0之后关于关于对话框的模块(messagebox.filedialog.colorchooser)都被收归到了tk ...
- 微信小程序 this和that详解及简单实例
微信小程序中,在wx.request({});方法调用成功或者失败之后,有时候会需要获取页面初始化数据data的情况,这个时候,如果使用,this.data来获取,会出现获取不到的情况,调试页面也会报 ...
- JDK 自带压缩解压流
代码如下 package com.test.java.zip; import java.io.BufferedInputStream; import java.io.BufferedOutputStr ...