JS小知识 从函数提升谈到闭包

327 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

10/13对例子与部分知识点进行更新&增添

学习了一下闭包~

  • 先来看个最简单的例子
 function Fun(){
     var a = 1;
     function foo(){
         console.log(a);
     }
 }
 console.log(Fun());// undefined
 // 由于内部函数调用 产生了闭包

嵌套的内部函数引用了外部函数的变量时就产生了闭包

闭包形成过程如下:

在这里插入图片描述

参考:详细解析 JavaScript 闭包 这篇文章真的非常全面 后面还配有一些不错的例子

很明显这个过程发生了函数提升!

在这里插入图片描述

通过chrome工具得知: 闭包本质是内部函数中的一个对象, 这个对象中包含引用的变量属性(上图中的a 且值为undefined)

再举一个复杂一些的例子

 function Fun(){
     var a = 1;
     function foo(){
         a++;
         console.log(a);
     }
     return foo
 }
 var f = new Fun();
 f();// 2
 f();// 3
 // 过程中foo被解析 调用了全局变量a 形成闭包(闭包对象为Fun)

其中发生的过程大家可以自行打断点看一下

比较重要的点是:

image.png

不管在Fun()函数中各个部分的a值为多少,在赋值语句 a=1 亮相的一刹那(就是a = 1执行发生时),所有a变为1

这一点在下面的代码中体现得很明显

10/13补充

需要额外注意一下, 上面那个例子使用 var foo = function(){}输出的结果相同,但是过程是有区别的!!

  function Fun(){
    var a = 1;
    var foo = function(){ 
        a++;
        console.log(a);
    }
        return foo
    }
    var f = new Fun();
    f();// 2
    f();// 3

image.png

打个断点看看

image.png

image.png

害!虽然在本例中输出结果都是一样的,但是有的问题中,这种给变量赋一个函数的方式与用function声明函数的最终输出是不同的!

本例中需要明白二者在执行时有何差异~!

小结下闭包形成的条件——

  • 【1】函数嵌套
  • 【2】内存函数中有(引用了)外层函数的变量(/函数)

闭包作用、应用、缺点

于10/13精简 + 完善 “闭包的缺点”部分内容

  • 闭包作用

    • 延长局部变量的生命周期
    • 让函数外部能操作内部的局部变量
  • 闭包的应用

    • 模块化——

      • 封装一些数据/操作数据的函数 向外暴露一些行为
    • 循环遍历 + 监听

    • JS框架(jQuery)中大量使用了闭包

  • 闭包的缺点

    • 可能导致内存溢出(面试高频)
     var obj = {};
     for(var i = 0; i < 10000; i++){
         obj[i] = new Array(1000000);// new Array(1000000)定义一个长度为1000000的数组
         console.log('------')
     }// 这个代码会导致内存溢出 浏览器会做一个崩溃的设置 终止程序
    

    内存溢出是指存储的数据超出了指定空间的大小,这时数据就会越界

    • 可能会导致内存泄露
     function fn1(){
         var arr = new Array[10000000]
         function fn2(){
             console.log(arr.length);
         }
         return fn2;
     }
     var f = fn1();
     f();// fn1形成闭包 本该释放的arr变量现在不会被释放!
    

    内存泄漏的意思:变量占用内存的事件可能会过长(毕竟延长了局部变量的生命周期嘛~ 申请的内存空间没有被正确释放,导致后续程序里这块内存被永远占用(不可达))——

    所以需要及时释放

    内部函数对象f成为垃圾对象!!

     f = null;// 解放空间!