美文网首页
JS基础核心之闭包

JS基础核心之闭包

作者: 付出的前端路 | 来源:发表于2020-08-21 09:22 被阅读0次

    1. 闭包是什么?

    function A () { // chrome认为的闭包是A函数
      var num = 1
      return function B () {
        console.log(num)
      }
    }
    var C = A ()
    // 函数A中的变量num被全局函数C引用着,以至于不会被垃圾回收机制回收
    C() // 1 // 大多数书籍理解的闭包是C函数
    

    在A函数中嵌套B函数,B函数访问A函数中的变量。将A函数复制给C函数并执行。

    那么在大多数的理解中,包括许多著名的书籍,文章里都以函数C的名字代指这里生成的闭包。而在chrome中,则以执行上下文A的函数名代指闭包。

    而我的理解是:闭包更准确的说是一项技术或者一个特性:只要运用具备阻止垃圾回收机制回收和突破作用域链限制的技术,就是闭包。像是《JavaScript权威指南》打的比方,像是把变量包裹了起来,形象的称为“闭包”。

    如果非要指明哪个函数是闭包的话,我愿意将A函数称为定义闭包的函数,C函数为执行闭包的函数。

    2 生成闭包的条件是什么?

    function foo() { // 定义闭包
        var a = 10;
        function baz() {
          console.log(a);
        }
        baz(); // 被确认创建闭包
    }
    
    baz();
    

    a. 在函数内部创建新的函数;

    b. 新的函数在执行时,访问了函数的变量对象。

    c. 闭包是在函数被调用执行的时候才被确认创建的。

    一句话总结:==函数中闭包判定的准则,即执行时是否在内部定义的函数中访问了上层作用域的变量。==

    3. 闭包的作用是什么?

    闭包,阻止垃圾回收机制。

    闭包,突破作用域链接。

    4 闭包的应用

    模块模式

    《你不知道的JS中》的示例:

    function coolModule () {
      // 私有变量和函数
      var something = 'cool';
      var another = [1, 2, 3]
      function doSomething () {
        console.log(something)
      }
      function doAnother () {
        console.log(another.join('!'))
      }
      // 公开方法
      return {
        doSomething,
        doAnother
      }
    })
    var foo = coolModule ()
    foo.doSomething() // cool
    foo.doAnother() // 1!2!3
    

    模块模式需要具备两个必要条件:

    1.必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)。

    2.封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。

    什么时候使用模块模式?

    如果必须创建一个对象并一某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,那么就可以使用模块模式。

    哪些地方有用到模块模式?

    最典型的就是JQuery库,jQuery和$标识符就是JQuery模块的公共API,但它们本身都是函数(由于函数也是对象,它们本身也可以拥有属性)

    以后单独拿一个章节,来具体讲讲现在的模块化和未来的模块化机制。

    柯里化

    具体的内容在函数的柯里化的章节中详细分析。

    戳此传送门

    面试题

    1. 防抖和节流
      戳此传送门
    1. 定时器
    for (var i = 1; i <= 5; i++) {
      setTimeout(function timer() {
        console.log(i); // 5次6
      }, i * 1000);
    }
    

    输出6的原因是:被封闭在一个共享的全局作用域中,实际上只有一个i。

    for (var i = 1; i <= 5; i++) {
      (function (j) {
        setTimeout(function timer() {
          console.log(j); // 依次输出1至5
        }, i * 1000);
      })(i)
    }
    

    依次输出1-5的原因是:在迭代内部使用IIFE(立即表达函数)为每个迭代生成一个新的作用域,将外部变量的值传递进去并被引用(阻止垃圾回收机制回收),使得每个回调函数都能访问到正确值的变量。

    1. jn-toast组件认识闭包

    戳此传送门

    相关文章

      网友评论

          本文标题:JS基础核心之闭包

          本文链接:https://www.haomeiwen.com/subject/aooyjktx.html