JS闭包的理解及常见应用场景

一、总结

一句话总结:

闭包是指有权访问另一个函数作用域中的变量的函数

1、如何从外部读取函数内部的变量,为什么?

闭包:f2可以读取f1中的变量,只要把f2作为返回值,就可以在f1外读取f1内部变
原因:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,f2的存在依赖f1,因此f1也始终存在内存中,不会在调用结束后,被垃圾回收机制回收。
function f1(){var n = 123;function f2(){    //f2是一个闭包
            alert(n)}    return f2;}js链式作用域:子对象会一级一级向上寻找所有父对象的变量,反之不行。

2、js链式作用域?

子对象会一级一级向上寻找所有父对象的变量,反之不行。
js中函数内部可以读取全局变量,函数外部不能读取函数内部的局部变量。

3、js变量两种作用域?

全局变量、局部变量(函数内):js中函数内部可以读取全局变量,函数外部不能读取函数内部的局部变量。

4、闭包为什么可以实现在函数外读取到函数内的变量?

|||-begin

function f1(){var n = 123;function f2(){    //f2是一个闭包
            alert(n)}    return f2;}

|||-end

原因:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,f2的存在依赖f1,因此f1也始终存在内存中,不会在调用结束后,被垃圾回收机制回收。

二、对JS闭包的理解及常见应用场景

转自或参考:对JS闭包的理解及常见应用场景
https://blog.csdn.net/qq_21132509/article/details/80694517

1、变量作用域

变量作用域两种:全局变量、局部变量。js中函数内部可以读取全局变量,函数外部不能读取函数内部的局部变量。

2、如何从外部读取函数内部的变量?

function f1(){var n = 123;function f2(){    //f2是一个闭包alert(n)}    return f2;}
js链式作用域:子对象会一级一级向上寻找所有父对象的变量,反之不行。
f2可以读取f1中的变量,只要把f2作为返回值,就可以在f1外读取f1内部变量

3、闭包概念

能够读取其他函数内部变量的函数。
或简单理解为定义在一个函数内部的函数,内部函数持有外部函数内变量的引用。

4、闭包用途

1、读取函数内部的变量
2、让这些变量的值始终保持在内存中。不会再f1调用后被自动清除。
3、方便调用上下文的局部变量。利于代码封装。
原因:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,f2的存在依赖f1,因此f1也始终存在内存中,不会在调用结束后,被垃圾回收机制回收。

5、闭包理解

/*** [init description]* @return {[type]} [description]*/
function init() {var name = "Chrome";    //创建局部变量name和局部函数alertNamefunction alertName() { //alertName()是函数内部方法,是一个闭包alert(name); //使用了外部函数声明的变量,内部函数可以访问外部函数的变量}alertName();
}
init();
//一个变量在源码中声明的位置作为它的作用域,同时嵌套的函数可以访问到其外层作用域中声明的变量/*** [outFun description]* @return {[type]} [description]*/
function outFun(){var name = "Chrome";function alertName(){alert(name);}return alertName;   //alertName被外部函数作为返回值返回了,返回的是一个闭包
}var myFun = outFun();
myFun();
/*
闭包有函数+它的词法环境;词法环境指函数创建时可访问的所有变量。
myFun引用了一个闭包,闭包由alertName()和闭包创建时存在的“Chrome”字符串组成。
alertName()持有了name的引用,
myFunc持有了alertName()的的访问,
因此myFunc调用时,name还是处于可以访问的状态。*//*** [add description]* @param {[type]} x [description]*/
function add(x){return function(y){return x + y;};
}var addFun1 = add(4);
var addFun2 = add(9);console.log(addFun1(2)); //6
console.log(addFun2(2));  //11
//add接受一个参数x,返回一个函数,它的参数是y,返回x+y
//add是一个函数工厂,传入一个参数,就可以创建一个参数和其他参数求值的函数。
//addFun1和addFun2都是闭包。他们使用相同的函数定义,但词法环境不同,addFun1中x是4,后者是5

6、闭包应用场景之setTimeout

//原生的setTimeout传递的第一个函数不能带参数setTimeout(function(param){alert(param)},1000)//通过闭包可以实现传参效果function func(param){return function(){alert(param)}}var f1 = func(1);setTimeout(f1,1000);

7、闭包应用场景之回调

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title></title><link rel="stylesheet" href="">
</head>
<style>body{font-size: 12px;}h1{font-size: 1.5rem;}h2{font-size: 1.2rem;}
</style>
<body><p>哈哈哈哈哈哈</p><h1>hhhhhhhhh</h1><h2>qqqqqqqqq</h2><a href="#" id="size-12">12</a><a href="#" id="size-14">14</a><a href="#" id="size-16">16</a><script>function changeSize(size){return function(){document.body.style.fontSize = size + 'px';};}var size12 = changeSize(12);var size14 = changeSize(14);var size16 = changeSize(16);document.getElementById('size-12').onclick = size12;document.getElementById('size-14').onclick = size14;document.getElementById('size-16').onclick = size16;//我们定义行为,然后把它关联到某个用户事件上(点击或者按键)。我们的代码通常会作为一个回调(事件触发时调用的函数)绑定到事件上
</script>
</body>
</html>

8、闭包应用场景之封装变量

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title>闭包模拟私有方法</title><link rel="stylesheet" href="">
</head>
<body>
<script>//用闭包定义能访问私有函数和私有变量的公有函数。var counter = (function(){var privateCounter = 0; //私有变量function change(val){privateCounter += val;}return {increment:function(){   //三个闭包共享一个词法环境change(1);},decrement:function(){change(-1);},value:function(){return privateCounter;}};})();console.log(counter.value());//0counter.increment();counter.increment();//2//共享的环境创建在一个匿名函数体内,立即执行。//环境中有一个局部变量一个局部函数,通过匿名函数返回的对象的三个公共函数访问。</script>
</body>
</html>

9、闭包应用场景之为节点循环绑定click事件

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title></title><link rel="stylesheet" href="">
</head>
<body><p id="info">123</p><p>E-mail: <input type="text" id="email" name="email"></p><p>Name: <input type="text" id="name" name="name"></p><p>Age: <input type="text" id="age" name="age"></p><script>function showContent(content){document.getElementById('info').innerHTML = content;};function setContent(){var infoArr = [{'id':'email','content':'your email address'},{'id':'name','content':'your name'},{'id':'age','content':'your age'}];for (var i = 0; i < infoArr.length; i++) {var item = infoArr[i];document.getElementById(item.id).onfocus = function(){showContent(item.content)}}}setContent()//循环中创建了三个闭包,他们使用了相同的词法环境item,item.content是变化的变量//当onfocus执行时,item.content才确定,此时循环已经结束,三个闭包共享的item已经指向数组最后一项。/*** 解决方法1     通过函数工厂,则函数为每一个回调都创建一个新的词法环境*/function showContent(content){document.getElementById('info').innerHTML = content;};function callBack(content){return function(){showContent(content)}};function setContent(){var infoArr = [{'id':'email','content':'your email address'},{'id':'name','content':'your name'},{'id':'age','content':'your age'}];for (var i = 0; i < infoArr.length; i++) {var item = infoArr[i];document.getElementById(item.id).onfocus = callBack(item.content)}}setContent()/*** 解决方法2        绑定事件放在立即执行函数中*/function showContent(content){document.getElementById('info').innerHTML = content;};function setContent(){var infoArr = [{'id':'email','content':'your email address'},{'id':'name','content':'your name'},{'id':'age','content':'your age'}];for (var i = 0; i < infoArr.length; i++) {(function(){var item = infoArr[i];document.getElementById(item.id).onfocus = function(){showContent(item.content)}})()//放立即执行函数,立即绑定,用每次的值绑定到事件上,而不是循环结束的值}}setContent()/*** 解决方案3        用ES6声明,避免声明提前,作用域只在当前块内*/function showContent(content){document.getElementById('info').innerHTML = content;};function setContent(){var infoArr = [{'id':'email','content':'your email address'},{'id':'name','content':'your name'},{'id':'age','content':'your age'}];for (var i = 0; i < infoArr.length; i++) {let item = infoArr[i];      //限制作用域只在当前块内document.getElementById(item.id).onfocus = function(){showContent(item.content)}}}setContent()
</script>
</body>
</html>

转载于:https://www.cnblogs.com/Renyi-Fan/p/11590231.html

JS闭包的理解及常见应用场景相关推荐

  1. 面试官:谈谈对JS闭包的理解及常见应用场景(闭包的作用)

    文章目录 对JS闭包的理解及常见应用场景(闭包的作用) 1.变量作用域 2.如何从外部读取函数内部的变量? 3.闭包概念 4.闭包用途 5.闭包的理解 6.闭包应用场景 setTimeout传参 回调 ...

  2. 浅谈对js闭包的理解

    闭包就是能够读取其他函数内部变量的函数.由于在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成"定义在一个函数内部的函数".在本质上,闭包是将函数内 ...

  3. 谈一谈对JS闭包的理解

    个人觉得理解闭包,首先要理解以下几个概念. 1.函数的作用域和作用域链 js不像java等其他类语言,它并不存在块级作用域,取而代之的是函数作用域,另一个变量作用域是全局作用域. 函数的作用域:变量在 ...

  4. js闭包的理解和作用

    一.为什么引入闭包 JS为每个变量对象定了作用域,在ES5 中只有全局作用域和函数作用域,没有块级作用域,由内向外形成作用域链,函数外部不能访问函数内部作用域的局部变量.在实际开发中会带来很多不便. ...

  5. js闭包的理解及应用场景

    函数的声明与执行 函数定义阶段 1.会在堆内存中开辟一个存储空间 把函数体放在这个空间里 函数中的所有变量不解析 2.把这个空间地址赋值给函数名 然后储存在栈内存中 函数调用阶段 1.根据函数名找到对 ...

  6. js闭包循环原因_常见的三个 JS 面试题

    本文不是讨论最新的 JavaScript 库.常见的开发实践或任何新的 ES6 函数.相反,在讨论 JavaScript 时,面试中通常会提到三件事.我自己也被问到这些问题,我的朋友们告诉我他们也被问 ...

  7. js闭包是什么?对js闭包的理解

    结合 MDN 官网中 JavaScript 章节中对闭包详解,我们需要理清的问题有,什么是闭包.闭包产生的条件.以及闭包的用途. 1.1 闭包的概念 闭包(closure)是一个函数以及其捆绑的周边环 ...

  8. js闭包的理解以及闭包中this的理解

    javascript 闭包.this 2016-01-25  js pl 闭包其实很好理解,但是由于经常把this和闭包绑在一起,从而加大了理解的难度,如果将他们分开考虑,那就清晰多了. 闭包 闭包并 ...

  9. JS / 闭包的理解

    闭包实际上就是一个函数,只不过这个函数有些特殊,它定义在另一个函数内部,通过它可以在 js 中模仿出访问 C++ 中的私有成员变量的效果. 代码如下: function Test() {var cou ...

最新文章

  1. Office中如何实现公式颜色的更改?
  2. linux+shell+整数计算器,Shell(())实现对整数进行数学运算
  3. PyQt5利用QPainter绘制各种图形
  4. GitHub 新手详细教程转载,亲测可用
  5. 【计网】计算机网络期末总复习-谢希仁(个人总结)理论概念
  6. 【C/C++16】_public.h,_public.cpp,_cmpublic.h
  7. 昆仑量子计算机只是云计算模拟吧,量子模拟赛题让大学生认识未来计算发展方向...
  8. ftp linux 服务器 麒麟_麒麟系统安装ftp
  9. linux命令忘了,Linux考试易忘命令
  10. android+qq底部界面,Android 高仿QQ 界面滑动效果
  11. 试题11 蒜头君的随机数(排序和去重)
  12. 互联网日报 | 1月10日 星期日 | 小米之家千店同开;蔚来发布首款旗舰轿车ET7;LVMH完成收购Tiffany...
  13. 我的 Serverless 实战 — Serverless 腾讯云文字识别(OCR)详细部署过程
  14. 元旦贺卡html,元旦贺卡祝福语
  15. 第二重要极限公式推导过程_土木考研 土力学第五章公式推导:抗剪强度理论...
  16. AlertManager配置参数解析
  17. CVPR 2020 之文本检测识别论文大盘点
  18. pic单片机c语言读eeprom,PIC单片机应用专题二内外EEPROM读写..doc
  19. Typo Forum
  20. 修复损坏的gz或tar.gz压缩文件之方法篇

热门文章

  1. 使用云服务器安装QEMU搭建嵌入式开发环境
  2. 网页制作中绝对路径和相对路径的区别
  3. AMD and CMD are dead之KMD.js版本0.0.2发布
  4. Office 2010 Multi-language Pack download
  5. 创建支持ssh的docker镜像
  6. kalman 滤波 演示与opencv代码
  7. 简单认识Hexo的目录结构
  8. SQLite编译(How To Compile SQLite)
  9. 索引的工作原理及其优缺点
  10. 众推平台架构——分布式爬虫