揭开JS闭包的面纱
今天看了关于js闭包方面的文章,还是有些云里雾里,对于一个菜鸟来说,学习闭包确实有一定的难度,不说别的,能够在网上找到一篇优秀的是那样的不易。
当然之所以闭包难理解,个人觉得是基础知识掌握的不牢,因为闭包牵扯到一些前面的东西,比如作用域\等等,如果连基本的作用域都没有弄清楚,自然不可能搞懂闭包,还有就是对js的实践比较少,因为你根本就不知道什么时候要用这东西,自然谈不上对闭包的深刻理解。
今天我就简单的说说我目前所理解的闭包,当然可能不完全正确,但是我相信会给你一定的启发。
首先我们来谈谈js中的变量,如果你不知道我为什么要说这些,那么你根本没有掌握js的基础,建议回头复习。
js中分:全局变量 和 局部变量
全局变量:可以在任意位置访问的量就叫全局变量
1 var age = 20;
2 function a(){
3 console.log(age); >>20
4 }
5 a();
局部变量:函数中用var定义的变量,只能在函数中访问这个变量,函数外部访问不了。
1 function a(){
2 var age = 20;
3 }
4 a();
5 console.log(age); >> Uncaught ReferenceError: age is not defined
注意点1:在函数中如果不使用var定义变量那么js引擎会自动添加成全局变量。
注意点2:全局变量从创建的那一刻起就会一直保存在内存中,除非你关闭这个页面,局部变量当函数运行完以后就会销毁这个变量,假如有多次调用这个函数它下一次调用的时候又会重新创建那个变量,既运行完就销毁,回到最初的状态,简单来说局部变量是一次性的,用完就扔,下次要我再重新创建。
函数的相关知识点:
1. 一个函数内可以嵌套多个函数
2. 函数里面的子函数可以访问它上级定义的变量,注意不只是一级,如果上级没有会继续往上级找,直到找到为止,如果找到全局变量到找不到就会报错。

1 function a(){
2 var name = "追梦子";
3 function b(){
4 console.log(name); >> "追梦子"
5 }
6 b();
7 }
8 a();

3. 函数的另外一种调用形式,你可以把它叫做自调用,自己调用自己,达到自执行的效果。
1 var a = 0;
2 (function(){
3 console.log(++a); >>1
4 })()
这种方式用()把内容包裹起来,后面的()表示执行这个函数,可能你会问为什么要把函数包起来,如果不包裹起来,js会把它当作函数声明来处理,如果包裹起来就是表达式,还没有看懂就上网查吧。
开始我们正式闭包部分---------------------------- 币包 ---------------像钱包一样的东西,可以把东西包裹起来----------
首先我们来看看为什么需要学习闭包,加以理解 -- 0 v 0- -
1 function a(){
2 var num = 0;
3 console.log(++num);
4 }
5 a(); >>1
6 a(); >>1
上面代码输出了两次1,为什么呢?如果你有看我上面的关于变量部分肯定能够想到个大概。
前面我们说过了函数执行完以后,里面的变量(即局部变量)就会销毁,下一次运行又会重新创建那个变量,所以虽然你第一次++num了但是这个变量在第一次执行完毕以后就被销毁了。
那么我们怎么样才能确保第一次的变量不被销毁,那么就需要我们的闭包出场了。
温馨提示:JavaScript中有回收机制,函数没有被引用执行完以后这个函数的作用域就会被销毁,如果一个函数被其他变量引用,这个函数的作用域将不会被销毁,(简单来说就是函数里面的变量会被保存下来,你可以理解成全局变量。)
…………………………………………………………………………………… 当 当 当 ................. 下面有请我们的币包同志

function a(){
var aa = ;
function b(){
aa ++;
console.log(aa);
}
return b;
}
var ab = a();
ab(); //1
ab(); //2

看到了吧里面的变量的值没有被销毁,因为函数a被外部的变量ab引用,所以变量aa没有被回收。
如果某个函数被它的父函数之外的一个变量引用,就形成了一个闭包
还有一种更为常用的闭包写法

var bi = (function(){
var a = ;
function b(){
a ++;
console.log(a);
}
return b;
})(); bi(); //1
bi(); //2
bi(); //3

执行过程分析:
首先把一个自执行函数赋值给了bi,这个自执行函数运行完成以后就bi的值就变成了
function b(){
a ++;
console.log(a);
}
因为我们在上面的代码return回去了b,然后因为这个自执行函数被bi引用所以里面的变量a并没有因为这个自执行函数执完而销毁,而是保存到了内存中,所以我们多次打印bi()就成了1、2、3
下面我来说一个闭包的使用场景吧。
没有使用闭包的版本

window.onload = function(){
var ul = document.getElementsByTagName("ul")[0];
var li = ul.getElementsByTagName("li");
for(var i=0;i<li.length;i++){
li[i].onclick = function(){
console.log(i); //不管我怎么点都是返回
}
}
}

使用了闭包的版本

window.onload = function(){
var ul = document.getElementsByTagName("ul")[0];
var li = ul.getElementsByTagName("li");
for(var i=0;i<li.length;i++){
(function(i){
li[i].onclick = function(){
console.log(i); //点击第几个返回第几个
}
})(i)
}
}

、、、、、如果你不理解这个,你只要这样子用就能够达到效果。
揭开JS闭包的面纱的更多相关文章
- js闭包的作用域以及闭包案列的介绍:
转载▼ 标签: it js闭包的作用域以及闭包案列的介绍: 首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...
- 大部分人都会做错的经典JS闭包面试题
由工作中演变而来的面试题 这是一个我工作当中的遇到的一个问题,似乎很有趣,就当做了一道题去面试,发现几乎没人能全部答对并说出原因,遂拿出来聊一聊吧. 先看题目代码: function fun(n,o) ...
- Js闭包常见三种用法
Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...
- ASP.NET 运行时详解 揭开请求过程神秘面纱
对于ASP.NET开发,排在前五的话题离不开请求生命周期.像什么Cache.身份认证.Role管理.Routing映射,微软到底在请求过程中干了哪些隐秘的事,现在是时候揭晓了.抛开乌云见晴天,接下来就 ...
- 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 ...
- 带你揭开ATM的神秘面纱
相信大家都用过ATM取过money吧,但是有多少人真正是了解ATM的呢?相信除了ATM从业者外了解的人寥寥无几吧,鄙人作为一个从事ATM软件开发的伪专业人士就站在我的角度为大家揭开ATM的神秘面纱吧. ...
- js闭包理解实例小结
Js闭包 闭包前要了解的知识 1. 函数作用域 (1).Js语言特殊之处在于函数内部可以直接读取全局变量 <script type="text/javascript"> ...
随机推荐
- Java8之方法引用
一.概述 在学习lambda表达式之后,我们通常使用lambda表达式来创建匿名方法.然而,有时候我们仅仅是调用了一个已存在的方法.如下: Arrays.sort(stringsArray,(s1,s ...
- Java8学习笔记(一)--Lambda表达式
两个概念 函数式接口 函数式接口就是只显式声明一个抽象方法的接口.为保证方法数量不多不少,java8提供了一个专用注解@FunctionalInterface,这样,当接口中声明的抽象方法多于或少于一 ...
- bootstrap浅谈
学习地址:http://www.runoob.com/bootstrap/bootstrap-tutorial.html 自己练习了下 主要是使用了bootstrap中包含的class类样式,只要给相 ...
- Numpy 系列(七)- 常用函数
在了解了 Numpy 的基本运算操作,下面来看下 Numpy常用的函数. 数学运算函数 add(x1,x2 [,out]) 按元素添加参数,等效于 x1 + x2 subtract(x1,x2 ...
- 如何实现Python调用C代码--python与C之间如何通信(swig)
转载: https://www.zhihu.com/question/23003213 1. C代码如何调用Python 1.1 test #include <Python.h> int ...
- ArcMap修改粘滞移动容差防止要素在选择时无意拖动移动
粘滞移动容差将设置一个最小像素数,鼠标指针必须在屏幕上移动了此最小距离时,所选要素才会实际发生移动. 设置粘滞移动容差的结果是延迟移动所选要素,直到指针至少移动了这段距离.此方法可用于在使用“编辑”工 ...
- gitlab升级和迁移
由于近期公司gitlab服务器老是卡顿和出现其他问题,然后也很久没有升级过了,现在版本还是8.10.5,而官网最新版本已经是11.2了.另一个原因是gitlab所在的这台服务器快到期了,想换一台配置更 ...
- springMVC中 @RequestParam和@RequestBody的区别
首先,不可以同时传进@RequestParam和@RequestBody,好像可以传进两个@RequestParam 如果不加@requestparam修饰,相当于 加上@requestparam且各 ...
- BMP文件解析
目录 BMP文件简介 BMP文件格式 位图头 位图信息 调色板 位图数据 C语言代码 获取文件大小 获取文件尺寸 获取文件偏移量 读取文件数据示例 一个问题 完整程序 BMP文件简介 BMP(全称Bi ...
- token的设置与获取
以用户登录为例: application-resources.yml: #用户session在redis中保存的key REDIS_STU_SESSION_KEY: REDIS_USER_SESSIO ...