闭包学习理解

本文深入探讨JavaScript中的闭包概念,它如何延伸变量的作用域,并通过示例说明闭包在函数内部访问外部变量的能力。闭包可用于模拟私有方法,避免作用域冲突,并在循环中创建独立的作用域。然而,需要注意的是,闭包可能导致性能问题,因为它会占用额外的内存。文章还讨论了如何在循环中正确创建闭包以防止常见的错误,并提供了优化技巧。
摘要由CSDN通过智能技术生成

闭包(closure) – 延伸了变量的作用域

  • 闭包:一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包closure)。指有权访问另一个函数作用域中变量的函数。

  • 闭包可以在一个内层函数中访问到其外层函数的作用域。延伸了变量的作用域

  • 在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

  • 示例1:

    // 外层函数 -- 声明一个变量;return 一个内部函数
    funciton fn() {
        var num = 0;
        // 内层函数
        return function() { // 调用外部函数 fn()的变量 num
            console.log(++num) // 延伸了num 作用域
        }
    }
    var fun = fn();
    fun(); // 打印结果为 1
    fun(); // 打印结果为 2
    

    在本例子中,fun 是执行 fn 时创建的函数实例(return 的函数)的引用。该函数的实例维持了一个对它的词法环境(变量 num存在于其中)的引用。因此,当fun被调用时,变量num` 仍然可用,所以打印结果为 1

  • 词法作用域

    词法(lexical):指的是,词法作用域根据源代码中声明变量的位置来确定该变量在何处可用。

    嵌套函数可访问声明于它们外部作用域的变量。

  • 示例2:

    function makeAdder(x) {
        return function(y) {
            return x + y;
        }
    }
    var add5 = makeAdder(5);
    var add10 = makeAdder(10);
    console.log(add5(2)); // 打印结果为 5
    console.log(add10(2)); // 打印结果为 12
    
    // 解析
    add5 = makeAdder(5) = function(y) = 5+y
    add5(2) = makeAdder(5) = function(2) = 5+2 = 7
    add10 = makeAdder(10) = function(y) = 10+y
    add10(2) = makeAdder(10) = function(2) = 10+2 = 12
    

    add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的词法环境。在 add5 的环境中,x为5。而在add10中,x则为10。

  • 用闭包模拟私有方法 – 面试时可能会问道

    私有方法的好处:

    • 利于限制对代码的访问;
    • 提供了管理全局命名空间的强大能力;
    • 避免非核心的方法弄乱代码的公共接口部分。
  • 在循环中创建闭包:一个常见错误 – 面试时可能会问道

    在for循环中创建闭包时,可能会因为闭包共享一个词法作用域,造成错误。

    解决方法:

    • 为每个闭包创建单独的词法环境

    • 使用匿名闭包

      示例:

      function showHelp(help) {
        document.getElementById('help').innerHTML = help;
      }
      
      function setupHelp() {
        var helpText = [
            {'id': 'email', 'help': 'Your e-mail address'},
            {'id': 'name', 'help': 'Your full name'},
            {'id': 'age', 'help': 'Your age (you must be over 16)'}
          ];
      
        for (var i = 0; i < helpText.length; i++) {
          (function() {
             var item = helpText[i];
             document.getElementById(item.id).onfocus = function() {
               showHelp(item.help);
             }
          })(); // 马上把当前循环项的item与事件回调相关联起来
        }
      }
      
      setupHelp();
      
    • 使用关键词 let 而非 var (let 关键字有作用域;var 关键字无作用域)

    • 可选方案 – 使用forEach()遍历数组

      function showHelp(help) {
        document.getElementById('help').innerHTML = help;
      }
      
      function setupHelp() {
        var helpText = [
            {'id': 'email', 'help': 'Your e-mail address'},
            {'id': 'name', 'help': 'Your full name'},
            {'id': 'age', 'help': 'Your age (you must be over 16)'}
          ];
      
        helpText.forEach(function(text) {
          document.getElementById(text.id).onfocus = function() {
            showHelp(text.help);
          }
        });
      }
      
      setupHelp()
      
  • 性能考量

    闭包的缺点:闭包在处理速度和内存消耗方面对脚本性能具有负面影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值