• 不断更新:整理常见的闭包问题


    不断积累和整理在JavaScript中常见的闭包问题,不断加深理解和学习运用:


     参考MDN网址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

    闭包的官方定义: 闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量(摘自MDN)

    闭包的简单理解:希望在另一个作用域(比如在global中)访问局部作用域中的某个变量或函数

    (在谷歌浏览器中调试,发生闭包会有closure字样提示)

    问题一:闭包的“雏形”:在全局作用域中访问某局部作用域中的变量或函数:

    function fn() {
    
      var name =  'zs';
    
      return function () {
    
        return name;  
    
      }
    
    }
    
    var f = fn();
    
    var n = f(); 
    
    //或者这样写: var n= fn()();
    
    console.log(n) //zs

    问题二:用闭包解决在for循环中绑定事件的问题

    假设不使用闭包解决这个问题,点击绑定的li的值输出的都是最后的一个值,因为触发点击事件的时候for循环已经结束了,且在for循环的作用域中 i 的值不断被覆盖

    var list = document.getElementByTagName('li');
    
    for (var i = 0 ;i < list.length ;i++){
        var li = list[i];
        ( function (index){
             li.onclick = function(){
                 alert( index );
            }    
        })(i)
    }    
    

    自执行函数从全局作用域中访问for循环里面的 i, 给每个 i 都新开创了一个作用域,让它保存i的值 

    但过多的开创独立作用域,会造成额外的开销消耗性能,所以闭包有利有弊,像上面这种问题可以使用let来解决

    延伸:其他解决改问题的方法(使用let定义i)

    var list = document.getElementByTagName('li');
    
    for (let i = 0 ;i < list.length ;i++){
             li.onclick = function(){
                 alert( i );
            }    
    }    

    问题三:用闭包解决在for循环中 setTimeout() 的问题

    console.log(111)
    for ( var i = 0 ; i<3 ; i++){
         setTimeout(function () {
              console.log(i)
        }, 0 )  
    }
    console.log(222)
    
    最后的执行结果:
    111
    222
    3
    3
    3
    

    当js执行到setTimeout时会将其自动放入异步队列中去等待,直到主代码执行完后再去执行异步队列中的代码,于是3个3会在最后出现

    使用闭包的方法避免这种情况:

    console.log(111)
    for ( var i = 0 ; i<3 ; i++){
        (function (index){
            setTimeout(function () {
              console.log(i)
            }, 0 )  
        })(i)
    }
    console.log(222)
    输出结果:
    111
    222
    0
    1
    2

    问题四:从闭包的角度给button等元素绑定事件demo

    <a href="#" id="size-12">12</a>
    <a href="#" id="size-14">14</a>
    <a href="#" id="size-16">16</a>
    function makeSizer(size) {
      return function() {
        document.body.style.fontSize = size + 'px';
      };
    }
    
    var size12 = makeSizer(12);
    var size14 = makeSizer(14);
    var size16 = makeSizer(16);
    document.getElementById('size-12').onclick = size12;
    document.getElementById('size-14').onclick = size14;
    document.getElementById('size-16').onclick = size16;

    size12size14 和 size16 三个函数将分别把 body 文本调整为 12,14,16 像素。我们可以将它们分别添加到按钮的点击事件上。

    总结:

     上面是闭包的几个典型例子,除此之外闭包常见的问题还有用闭包模拟私有方法等等,同时要注意开创闭包后要给它赋值为null来清除,避免其常驻内存,造成内存泄漏等问题影响性能,当然还有其他方式。

    闭包考量性能,既实用,同时也有弊端。

    运用好闭包是掌握JS的重点之一。革命尚未成功,同志仍需努力!

  • 相关阅读:
    MVC 中301永久重定向
    String
    redis key设置过期时间
    hbase java 增加列族
    hbase 物理存储
    java 类图
    SSH hql中文查询时乱码快速解决
    json和pickle的序列化与反序列化
    python之生成器与迭代器
    安装traits库心得
  • 原文地址:https://www.cnblogs.com/lwj-blog/p/11357441.html
Copyright © 2020-2023  润新知