博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
js深入之闭包使用实例
阅读量:7029 次
发布时间:2019-06-28

本文共 2480 字,大约阅读时间需要 8 分钟。

(本篇适用于对js闭包有一定基础的读者)

使用闭包有以下几大好处:

   a:希望一个变量长期驻扎在内存中。
   b:避免全局变量的污染。
js闭包的特性
  a:闭包的外层是个函数,闭包内部有函数。
  b:闭包会return内部函数,闭包返回的函数内部不能有return。(如果有会结束闭包)
  c:执行闭包后,闭包的内部变量会存在,闭包内部函数的内部变量会回收。

1、基础实例1:

function A() {

  let count = 0

  function B() {

     count++

     console.log(count)

  }

}

var C = A(); //通过C这样一个外部变量可以访问到A的内部变量

C(); //1

C();  //2

C();  //3

 函数A的内部函数B被函数A的一个变量C引用:
当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。

2、基础实例2:
function count() {

 var arr = []; 

 for (var i=1; i<=3; i++) { 

    arr.push(function () { 

      return i * i; 

 }); 

 } 

 return arr;

}

var results = count();

var f1 = results[0];

var f2 = results[1];

var f3 = results[2];

// 在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都添加到一个Array中返回了。

// 你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果是:
f1(); // 16

f2(); // 16

f3(); // 16

全部都是16!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了4,因此最终结果为16。

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
function count() { 

 var arr = []; 

 for (var i=1; i<=3; i++) { 

   arr.push((function (n) { 

     return function () { 

       return n * n; 

     } 

 })(i));

}

return arr;

}

var results = count();

var f1 = results[0];

var f2 = results[1];

var f3 = results[3];

f1(); //1

f2(); //4

f3(); //9

注意这里用了一个“创建一个匿名函数并立刻执行”的语法:

3、闭包在IE下内存泄露问题:
IE9之前,JScript对象和COM对象使用不同的垃圾收集例程,那么闭包会引起一些问题。
创建一个闭包,而后闭包有创建一个循环引用,那么该元素将无法销毁。常见的就是dom获取的元素或数组的属性(或方法)再去调用自己属性等。例如:
function handler(){ 

 var ele = document.getElementById("ele"); 

 ele.onclick = function(){ 

 alert(ele.id); 

 }

闭包会引用包含函数的整个活动对象,即是闭包不直接引用ele,活动对象依然会对其保存一个引用,那么设置null就可以断开保存的引用,释放内存。代码如下:

function handler(){ 

 var ele = document.getElementById("ele"); 

 var id = ele.id; 

 ele.onclick = function(){ 

 alert(id); } ele = null;

}

console.log('cache', cache);

4、js闭包缓存机制:

设想我们需要向接口请求所需数据,又不想保存在全局变量中,并且会多次使用,那么我们就需要将请求的数据存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则调用API,然后设置缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正好可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。
示例:

const getList = (function() { 

 let data = {}; 

 const getData = () => { 

      return new Promise((resolve, reject) => { 

            let packageOptions = { url: '/your/api', params: { normal: 1 }, 

                success: function (rsp) { 

                           data = rsp.data; resolve(); 

                         } 

            };         

          ajax(packageOptions); 

     }) 

 } 

 // 闭包存储data 

 const result = async function (type) { 

 if (JONS.stringify(data) === '{}') { 

   await getData(); 

  return data; 

   } else {

 

 return data; 

 } 

 } 

 return result;

})();

// 第一次调用通过api请求数据

getList().then(res => { 

 console.log(res); 

 // 第二次调用则直接拿取缓存数据 

 getList().then(res => { console.log(res); })

})

本文仅作为个人记忆点存储

参考文章:

转载于:https://juejin.im/post/5ce10c7cf265da1b725bd228

你可能感兴趣的文章
OS开发过程中常用开源库
查看>>
关于在多个UItextield切换焦点
查看>>
hdu 2768
查看>>
git记住用户名密码
查看>>
ElasticSearch(2)-安装ElasticSearch
查看>>
从mysql数据表中随机取出一条记录
查看>>
ORACLE 锁表处理,解锁释放session
查看>>
深海机器人问题
查看>>
正则表达式(括号)、[中括号]、{大括号}的区别小结
查看>>
88.NODE.JS加密模块CRYPTO常用方法介绍
查看>>
java.net.ProtocolException: Exceeded stated content-length of: '13824' bytes
查看>>
asp.net 连接 oracle10g 数据库
查看>>
C 入门 第十一节
查看>>
HTML简单的注册页面搭建
查看>>
【06】Vue 之 组件化开发
查看>>
Docker 安装
查看>>
多数据库数据导入
查看>>
[AVR]高压并行编程---基础知识
查看>>
inl文件介绍
查看>>
前端坑--表单篇
查看>>