一段代码理解闭包

##实现基本的闭包

####返回一个函数

// 注释: 定义fn接收函数只执行后返回的对象(函数或者包含函数的对象)
// a为要控制的数据变量,方法fn1,fn2控制这个局部变量a
var fn = (function (){
        var a;
        a = 1;
        return function () {
            a += 2;
            alert(a);
        }
        })()
    // 测试代码
    fn(); // 执行a+=2;,输出结果为3
    fn();// 执行a+=2;,输出结果为5
    fn = null; // 垃圾回收,释放内存

####返回一个包含方法的对象

// 注释: 定义fn接收函数只执行后返回的对象(函数或者包含函数的对象)
// a为要控制的数据变量,方法fn1,fn2控制这个局部变量a
var fn = (function (){
        var a,fn1,fn2; // 局部私有变量和方法
        a = 1;
        fn1 = function (){
            a++;
            return a;
        }
        fn2 = function (){
            a--;
            return a;
        }
        return {
            fn1:fn1,
            fn2:fn2
        }
    })()
    
    // 测试代码
    console.log(fn.fn1()); // 执行a++,输出结果为2
    console.log(fn.fn2());// 执行a--,输出结果为1
    console.log(fn.fn1());// 执行a++,输出结果为2
    fn = null; // 垃圾回收

##闭包解决循环内嵌异步函数(事件驱动的函数或定时器函数) ####1.错误的方法

<!DOCTYPE html>
<html xml:lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
    <title>闭包解决循环问题</title>
     <style>
            li {
                height: 30px;
                width: 100px;
                text-align: center;
                line-height: 30px;
                background-color: pink;
                margin-top: 10px;
            }
    </style>
</head>
<body>
<ul>
    <li>列表1</li>
    <li>列表2</li>
    <li>列表3</li>
    <li>列表4</li>
</ul>

<script>
    
var Lis = document.getElementsByTagName('li');
for (var i = 0; i < Lis.length; i++) {
    // 依次给每个li标签注册事件
    Lis[i].onclick = function () {        
        alert(i); // 点击列表1,输出4;点击列表2,输出的也是4;点击3,4结果亦同;
    };
}
</script>
</body>
</html>

####2.运用闭包解决上面问题,只需要改写script标签里的JavaScript代码

   var Lis = document.getElementsByTagName('li');
   for (var i = 0; i < Lis.length; i++) {
       Lis[i].onclick = (function (i) {     
           return function (){
               alert(i); // 点击列表0,输出0;点击列表1,输出1;成功输出正确的值
               // 用闭包包裹变量 i 后,并将全局i通过传参的方式传入,i 变成了函数内的一个局部私有变量,
               // return出的这个事件执行函数里访问不再是全局的 i,而是这个局部变量 i ,此时就能正确输出;
           }
       })(i);
       Lis[i] = null;
   }

####3.当然,闭包并不是解决这个问题的最佳方法,因为闭包存在内存泄露问题尽量不要使用,下面介绍一种通过给DOM节点设置自定义属性方式解决这个问题

   var Lis = document.getElementsByTagName('li');
   for (var i = 0; i < Lis.length; i++) {
       Lis[i].index = i;
       Lis[i].onclick = function () {       
           alert(this.index); // 这里的this指向,调用他的当前DOM节点,也就是当前的 li 标签
       };
   }

####4.最好的方法自然是ES规范里的东西,利用ES6新标签let来解决上面问题

 var Lis = document.getElementsByTagName('li');
   // 很简单只需要把var 改成let就行了,这是i就认为是一个局部块级作用域
  // 这种方法虽然简单,但是ES6浏览器还没有被普遍支持,所以我们一般用Babel对它进行转译后才能使用。
   for ( let i = 0; i < Lis.length; i++) {
       Lis[i].onclick = function () {    
           alert(i);
       };
   }
// 温馨提示:关于let的详细用法请参考阮一峰的ES6入门,http://es6.ruanyifeng.com/

本人Github账号:https://github.com/PandaTsui

转载于:https://my.oschina.net/PandaTsui/blog/756229

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值