JavaScript 闭包的使用场景


Posted in Javascript onSeptember 17, 2020

一、闭包

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,闭包就是能够读取其他函数内部变量的函数。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

比如下面的代码:

function f1() {
 var n = 999;
 function f2() {
 console.log(n);
 }
 return f2;
}
var result = f1();
result();//999

函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。

这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,就可以在f1外部读取它的内部变量了。

二、闭包的使用场景

1.setTimeout

原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。

function f1(a) {
 function f2() {
  console.log(a);
 }
 return f2;
}
var fun = f1(1);
setTimeout(fun,1000);//一秒之后打印出1

2.回调

定义行为,然后把它关联到某个用户事件上(点击或者按键)。代码通常会作为一个回调(事件触发时调用的函数)绑定到事件。

比如下面这段代码:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>测试</title>
</head>
<body>
 <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="size-12">12</a>
 <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="size-20">20</a>
 <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="size-30">30</a>

 <script type="text/javascript">
  function changeSize(size){
   return function(){
    document.body.style.fontSize = size + 'px';
   };
  }

  var size12 = changeSize(12);
  var size14 = changeSize(20);
  var size16 = changeSize(30);

  document.getElementById('size-12').onclick = size12;
  document.getElementById('size-20').onclick = size14;
  document.getElementById('size-30').onclick = size16;

 </script>
</body>
</html>

当点击数字时,字体也会变成相应的大小。

3.函数防抖

在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

实现的关键就在于setTimeOut这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现。

如下代码所示:

/*
* fn [function] 需要防抖的函数
* delay [number] 毫秒,防抖期限值
*/
function debounce(fn,delay){
 let timer = null //借助闭包
 return function() {
  if(timer){
   clearTimeout(timer) //进入该分支语句,说明当前正在一个计时过程中,并且又触发了相同事件。所以要取消当前的计时,重新开始计时
   timer = setTimeOut(fn,delay) 
  }else{
   timer = setTimeOut(fn,delay) // 进入该分支说明当前并没有在计时,那么就开始一个计时
  }
 }
}

4.封装私有变量

如下面代码:用js创建一个计数器

方法1:

function f1() {
 var sum = 0;
 var obj = {
  inc:function () {
   sum++;
   return sum;
  }
};
 return obj;
}
let result = f1();
console.log(result.inc());//1
console.log(result.inc());//2
console.log(result.inc());//3

在返回的对象中,实现了一个闭包,该闭包携带了局部变量x,并且,从外部代码根本无法访问到变量x。

方法2:

function f1() {
 var sum = 0;
 function f2() {
  sum++;
  return f2;
 }
 f2.valueOf = function () {
  return sum;
 };
 f2.toString = function () {
  return sum+'';
 };
 return f2;
}
//执行函数f1,返回的是函数f2
console.log(+f1());//0
console.log(+f1()())//1
console.log(+f1()()())//2

所有js数据类型都拥有valueOf和toString这两个方法,null除外
valueOf()方法:返回指定对象的原始值。
toString()方法:返回对象的字符串表示。
在数值运算中,优先调用了valueOf,字符串运算中,优先调用toString
sum+' '是一个字符串类型的数据

以上就是JavaScript 闭包的使用场景的详细内容,更多关于JavaScript 闭包的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
javascript prototype 原型链
Mar 12 Javascript
浅谈Javascript 执行顺序
Dec 18 Javascript
jquery遍历select元素(实例讲解)
Dec 31 Javascript
sencha ext js 6 快速入门(必看)
Jun 01 Javascript
jQuery实现最简单的切换图效果【可兼容IE6、火狐、谷歌、opera等】
Sep 04 Javascript
Node.js的Mongodb使用实例
Dec 30 Javascript
react-router中的属性详解
Jun 01 Javascript
Vue学习之路之登录注册实例代码
Jul 06 Javascript
fetch 如何实现请求数据
Dec 20 Javascript
vue tab滚动到一定高度,固定在顶部,点击tab切换不同的内容操作
Jul 22 Javascript
解决vuex数据页面刷新后初始化操作
Jul 26 Javascript
NestJs使用Mongoose对MongoDB操作的方法
Feb 22 Javascript
javascript贪吃蛇游戏设计与实现
Sep 17 #Javascript
js实现简单的随机点名器
Sep 17 #Javascript
谈谈JavaScript中的垃圾回收机制
Sep 17 #Javascript
js对象属性名驼峰式转下划线的实例代码
Sep 17 #Javascript
详细分析JavaScript中的深浅拷贝
Sep 17 #Javascript
js实现鼠标滑动到某个div禁止滚动
Sep 17 #Javascript
原生js+css实现tab切换功能
Sep 17 #Javascript
You might like
php中处理模拟rewrite 效果
2006/12/09 PHP
smarty基础之拼接字符串的详解
2013/06/18 PHP
php快速查找数据库中恶意代码的方法
2015/04/01 PHP
php使用CutyCapt实现网页截图保存的方法
2016/10/03 PHP
php使用curl伪造来源ip和refer的方法示例
2018/05/08 PHP
thinkPHP框架中layer.js的封装与使用方法示例
2019/01/18 PHP
PHP标准库(PHP SPL)详解
2019/03/16 PHP
PHP设计模式(六)桥连模式Bridge实例详解【结构型】
2020/05/02 PHP
IE不出现Flash激活框的小发现的js实现方法
2007/09/07 Javascript
javascript 极速 隐藏/显示万行表格列只需 60毫秒
2009/03/28 Javascript
Js event事件在IE、FF兼容性问题
2011/01/01 Javascript
Webkit的跨域安全问题说明
2011/09/13 Javascript
如何使Chrome控制台支持多行js模式——意外发现
2013/06/13 Javascript
javascript字母大小写转换的4个函数详解
2014/05/09 Javascript
基于promise.js实现nodejs的promises库
2014/07/06 NodeJs
js实现iframe框架取值的方法(兼容IE,firefox,chrome等)
2015/11/26 Javascript
在WordPress中加入Google搜索功能的简单步骤讲解
2016/01/04 Javascript
iframe中使用jquery进行查找的方法【案例分析】
2016/06/17 Javascript
vue自定义指令实现v-tap插件
2016/11/03 Javascript
Vue.js中组件中的slot实例详解
2017/07/17 Javascript
jquery中done和then的区别(详解)
2017/12/19 jQuery
vue导出html、word和pdf的实现代码
2018/07/31 Javascript
node实现爬虫的几种简易方式
2019/08/22 Javascript
js判断浏览器的环境(pc端,移动端,还是微信浏览器)
2020/12/24 Javascript
Python实现检测服务器是否可以ping通的2种方法
2015/01/01 Python
编写Python脚本把sqlAlchemy对象转换成dict的教程
2015/05/29 Python
在Pandas中DataFrame数据合并,连接(concat,merge,join)的实例
2019/01/29 Python
PyQt5下拉式复选框QComboCheckBox的实例
2019/06/25 Python
Python列表(list)所有元素的同一操作解析
2019/08/01 Python
Python实现随机爬山算法
2021/01/29 Python
台湾专柜女包:KINAZ
2019/12/26 全球购物
使用索引有什么好处
2016/07/27 面试题
Linux中如何用命令创建目录
2016/12/02 面试题
经管应届生求职信范文
2014/05/18 职场文书
档案工作个人总结
2015/03/03 职场文书
导游词之山海关
2019/12/10 职场文书