阅读 135

探索js闭包的由来与应用场景(js闭包的定义和用途)

一句话闭包

  • 闭包允许函数访问并操作函数外部的变量 --JS 忍者秘籍

  • 闭包是指有权访问另外一个函数作用域中的变量的函数 -- 红宝书

  • 闭包是指那些能够访问自由变量的函数,这里的自由变量是外部函数作用域中的变量 -- MDN

作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。
变量的作用域主要两种:全局作用域和函数作用域。
其次:块级作用域
先看下面一段代码

  // 全局作用域   var a = 1;   var f = 5;   function fu() {// 函数作用域     var a = 2;     var b = 3;     console.log(a, f); // 2, 5   }   fu();   console.log(a); //  1   // console.log(b); //  b is not defined   if (true) {// 块级作用域     var c = 5;     let d = 6;   }   console.log(c); //  5   // console.log(d); //  d is not defined 复制代码

我们通过上面这段代码,发现Javascript语言的一些特殊之处:

  • 函数内部可以直接读取全局变量

  • 函数外部无法读取函数内的局部变量(b is not defined)

  • 块级作用域内通过let、const创建的变量在外部无法读取, 详解(d is not defined)

作用链

当可执行代码内部访问变量时,会先查找本地作用域,如果找到目标变量即返回,否则会去父级作用域继续查找...一直找到全局作用域, 没找到则报错 XXX is not defined

闭包的形成

先看一下这个列子 列1:

    var b =13     function foo(){         var b =14         return function fo(){             console.log(b)          }     }     foo()() // 14 复制代码

我们可能会觉得很奇怪,上面的代码不是相当于下面这样子么? 列2:

    var b =13     function fo(){             console.log(b)      }     fo() // 13 复制代码

我们在看下这列子,发现与列2同理。 列3:

    var b =13     function foo(){         return function fo(){             console.log(b)          }     }     foo()(); // 13 复制代码

解析下以红宝书为列:闭包是指有权访问另外一个函数作用域中的变量函数
画下重点:

  • 访问另外一个函数作用域中的变量

  • 是一个函数

从中可得列1是一个闭包

    var b =13     function foo(){         var b =14         return function fo(){ // 一个函数             // 这里访问了另外一个函数作用域中的变量(访问了foo函数作用域的变量b)             console.log(b)          }     }     foo()() // 14 复制代码

闭包的作用

实现模块化,保护私有变量不被外部侵扰。
常见方法使用自执行函数实现闭包模块化

// 自执行函数实现模块化 // 模块1 (function () {     var a = 1;     console.log(a); // 1 })(); // 模块2 (function () {     var a = 2;     console.log(a); // 2 })(); 复制代码

模块1、模块2的a变量互不侵扰。

闭包的问题

    function father(){         var b =14         return function child(){             console.log(b)          }     }     foo()() // 14 复制代码

解析下上面闭包代码, father 函数作用域隔绝了外部环境,所有变量引用都在函数内部完成,father 运行完成以后,内部的变量就应该被销毁,内存被回收。然而闭包导致了全局作用域始终存在一个 child 函数在引用着 father 内部的 b 变量,这就意味着 father 内部定义的 child 函数引用数始终为 1,垃圾运行机制就无法把它销毁。引擎无法判断你什么时候还会调用闭包函数,只能一直让这些数据占用着内存, 从而导致 内存泄露

内存泄露 是指当一块内存不再被应用程序使用的时候,由于某种原因,这块内存没有返还给操作系统或者内存池的现象。内存泄漏可能会导致应用程序卡顿或者崩溃。

经典面试题

问:分析它实际运行的结果

    for (var i = 0; i < 3; i++) {          setTimeout(() => console.log(i),0);      }     // 3 3 3 复制代码

问:改造它,输出0 1 2
1.es6

    for (let i = 0; i < 3; i++) {          setTimeout(() => console.log(i),0)     }     // 0 1 2 复制代码

2.setTimeout第三个参数

    for (var i = 0; i < 3; i++) {          setTimeout((t) => console.log(t),0,i)     }     // 0 1 2 复制代码

3.闭包

    for (var i = 0; i < 3; i++) {         (function () {console.log(i)})()     }     // 0 1 2


作者:逆风起飞
链接:https://juejin.cn/post/7047439466184572958


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐