JavaScript(8)--- 闭包
JavaScript(8)--- 闭包
理解闭包 我的理解是:闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以简单这样理解
"函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者是数据,此时形成了闭包"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
一、闭包的由来
1、函数嵌套函数
JS之所以会有闭包,是因为JS不同于其他规范的语言,JS允许一个函数中再嵌套子函数,正是因为这种允许函数嵌套,导致JS出现了所谓闭包。
function a(){
var a=1;
function b(){
alert(a);
};
b();
}
a();
在JS正常的函数嵌套中,父函数a调用时,嵌套的子函数b的结构,在内存中产生,然后子函数又接着调用了,子函数b就注销了,此时父函数a也就执行到尾,父函数a也会把
自己函数体内调用时生成的数据从内存都注销。
function a(){
var a=1;
function b(){
alert(a);
}
return b;
}
var f=a();
这个例子中,父函数调用时,函数体内创建了子函数b,但是子函数并没有立即调用,而是返回了函数指针,以备“日后再调用”,因为“准备日后调用”,此时父函数a执行完了
也不敢注销自己的作用域中的数据,因为一旦注销了,子函数b日后再调用时,沿着函数作用域链往上访问数据,就没有数据可以访问了,这就违背了JS函数作用域链的机制。
正因此,子函数要“日后调用”,导致父函数要维持函数作用域链,而不敢注销自己的作用域,那么这个子函数就是“闭包函数”。
2、JS变量的作用域
理解闭包还要理解一个知识点就是 JavaScript的变量作用域。与大多数语言相同,JavaScript变量的作用域分为全局变量和局部变量。**函数内部可以访问全局变量,但是
函数外部无法访问函数内部的局部变量**
示例
function f1(){
let n =100;
var m=99;
console.log(n);
console.log(m);
}
f1(); //输出:100 , 99
console.log(n); //输出:undefined
console.log(m); //输出:undefined
注意 在函数内部声明变量的时候一定要用let或者var。否则,实际上声明了一个全局变量
思考 函数外部如何读取局部变量?
要在函数外部读取局部变量,可以通过在函数内部再定义一个函数的方法来实现。
示例
function f1(){
var n =100;
function f2(){
console.log(n);
}
return f2;
}
let result =f1();
result(); //输出100
在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript
语言特有的"链式作用域"结构,子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
二、闭包的作用
闭包可以用在许多地方。它的最大用处有两个 1、可以读取函数内部的变量。2、让变量的值始终保持在内存中。
第一个上面已经实现了,这里就不再重复说明。
1、让变量的值始终保持在内存中
一般来说,全局变量的生存周期是永久的,直到我们主动销毁。而在函数内的局部变量来说,当退出函数时,这些函数变量立即失去它们的价值,也就被垃圾回收机制
销毁了,也算寿终正寝。
示例
//普通的函数
function f1() {
var num = 10;
num++;
return num;
}
console.log(f1()); //11
console.log(f1()); //11
console.log(f1()); //11
可是在闭包中,却不是这样。它可以让这些变量的值使用保持在内存中(不被垃圾回收)
示例
//函数模式的闭包
function f2() {
var num = 10;
function f3() {
num++;
return num;
}
return f3;
}
var ff = f2();
console.log(ff());//11
console.log(ff());//12
console.log(ff());//13
由此可见,当退出函数后,局部变量 num 并没有立即消失,一直存在,这样在第二次调用时 num 才会是在 11的基础上加1,是12,以后每次调用也才会不断加1。
思考 为什么会这样呢?
原因就在于f2是f3的父函数,而f3被赋给了一个全局变量,这导致f3始终在内存中,而f3的存在依赖于f2,因此f2也始终在内存中,不会在调用结束后,被垃圾回收机制
(garbage collection)回收。
三、示例
为了更好理解闭包在实际开发中的应用,这里举几个简单例子来说明闭包。
1、产生三个随机数,但是都是相同的
代码
<script>
//非闭包
function showRandom() {
var num=parseInt(Math.random()*10+1);
console.log(num);
}
showRandom(); //随机
showRandom(); //随机
showRandom(); //随机
console.log("===========================");
//闭包的方式,产生三个随机数,但是都是相同的
function f1() {
//这个只执行一次
var num=parseInt(Math.random()*10+1);
return function () {
console.log(num);
}
}
var ff=f1();
ff(); //这里三个值都是一样的
ff();
ff();
</script>
运行结果

2、点赞示例
先展示运行结果

代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>点赞应用</title>
<style>
ul {
list-style-type: none;
}
li {
float: left;
margin-left: 10px;
}
img {
width: 200px;
height: 180px;
}
input {
margin-left: 30%;
}
</style>
</head>
<body>
<ul>
<li><img src="images/ly.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
<li><img src="images/lyml.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
<li><img src="images/fj.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
<li><img src="images/bd.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
</ul>
<script>
//获取所有的按钮
//根据标签名字获取元素
function my$(tagName) {
return document.getElementsByTagName(tagName);
}
//闭包缓存数据
function getValue() {
var value=2;
return function () {
//每一次点击的时候,都应该改变当前点击按钮的value值
this.value="赞("+(value++)+")";
}
}
//获取所有的按钮
var btnObjs=my$("input");
//循环遍历每个按钮,注册点击事件
for(var i=0;i<btnObjs.length;i++){
//注册事件
btnObjs[i].onclick=getValue();
}
</script>
</body>
</html>
参考
1、js闭包的本质
2、JS闭包系列
4、js 闭包
别人骂我胖,我会生气,因为我心里承认了我胖。别人说我矮,我就会觉得好笑,因为我心里知道我不可能矮。这就是我们为什么会对别人的攻击生气。
攻我盾者,乃我内心之矛(5)。
JavaScript(8)--- 闭包的更多相关文章
- 深入理解JavaScript的闭包特性如何给循环中的对象添加事件
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- JavaScript作用域闭包简述
JavaScript作用域闭包简述 作用域 技术一般水平有限,有什么错的地方,望大家指正. 作用域就是变量起作用的范围.作用域包括全局作用域,函数作用域以块级作用域,ES6中的let和const可以形 ...
- JavaScript的闭包原理
什么是js(JavaScript)的闭包原理,有什么作用? 一.定义 官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 个人的理解是 ...
- Js(javaScript)的闭包原理
问题?什么是js(javaScript)的闭包原理,有什么作用? 一.定义 官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 小编 ...
- 深入理解javascript的闭包
闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...
- 如何给循环中的对象添加事件--深入理解JavaScript的闭包特性
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- javascript,jquery(闭包概念)(转)
偶尔听人说javascript闭包,让我联想起以前学编译原理和数字逻辑里讲的闭包,以前上课讲的闭包很难懂,而且含有递归的意思在里面,现在不想再查看里面的闭包概念. 但javascript我是经常要用, ...
- 理解Javascript 的闭包(closure)
要理解闭包的概念先从变量的作用域说去 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之 ...
- 两个示例介绍JavaScript的闭包
JavaScript的闭包有两个用途:一个是访问函数内部的变量:另一个是让变量的值在作用域内保持不变.函数是JavaScript 中唯一有作用域的对象,因此JavaScript的闭包依赖于函数实现,下 ...
- javascript 关于闭包的知识点
javascript 关于闭包的认识 概念:闭包(closure)是函数对象与变量作用域链在某种形式上的关联,是一种对变量的获取机制. 所以要大致搞清三个东西:函数对象(function object ...
随机推荐
- 转:get value from agent failed: ZBX_TCP_READ() failed;[104] connection reset by peer
get value from agent failed: ZBX_TCP_READ() failed;[104] connection reset by peer zabbix都搭建好了,进行一下测试 ...
- failed to load main-class manifest attribute(运行jar包出错)
原因描述:MANIFEST.MF文件中的Main-Class配置不正确或格式不正确 检查方式:以WinRarR的方式打开jar包,如图所示, 点击进入箭头所指的META-INF文件夹 将MAN ...
- ActiveMQ学习总结(一)
自己写的网上商城项目中使用了ActiveMQ,虽然相比于RabbitMQ,kafka,RocketMQ等相比,ActiveMQ可能性能方面不是最好的选择,不过消息队列其实原理区别不大,这里对学过的关于 ...
- golang实现chunk方式的查询
有一个需求,是把表里面所有的数据都查询出来,并且生成json文件.因为一张表里面的数据很多,所以不可能一次性全部查询出来,所以需要用到chunk.之前用的gorm,但是发现gorm没有chunk方式的 ...
- Yii的自带缓存的使用
Yii的自带缓存都继承CCache 类, 在使用上基本没有区别缓存基础类 CCache 提供了两个最常用的方法:set() 和 get().要在缓存中存储变量 $value,我们选择一个唯一 ID 并 ...
- 使用python抓取汽车之家车型数据
import requests import pymysql HOSTNAME = '127.0.0.1' USERNAME = 'root' PASSWORD = 'zyndev' DATABASE ...
- Python 中的集合 --set
前言 在Python中,我们用[]来表示列表list,用()来表示元组tuple,那{}呢?{}不光可用来定义字典dict,还可以用来表示集合set. 集合 set 集合(set)是一个无序的不重复元 ...
- The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path index.jsp页面出现错误的解决方法
点击项目名称>>>点击Buid Path>>>点击右侧add library>>>点击Server Runtime>>>点击 ...
- 前端、HTML+CSS+JS编写规范(终极版)
HTMLCSS文档规范 HTML和CSS文档必须采用UTF-8编码格式: HTML文档必须使用HTML5的标准文档格式: HTMLCSS编写规范 HTML和CSS的标签.属性.类名.ID都必须使用小写 ...
- 【30分钟学完】canvas动画|游戏基础(6):坐标旋转探究
前言 本篇主要讲坐标旋转及其应用,这是编程动画必不可少的技术. 阅读本篇前请先打好前面的基础. 本人能力有限,欢迎牛人共同讨论,批评指正. 坐标旋转 模拟场景:已知一个中心点(centerX,cent ...