zoukankan      html  css  js  c++  java
  • JavaScript | 彻底搞懂JS闭包

    闭包是js开发惯用的技巧,什么是闭包?

    闭包指的是:能够访问另一个函数作用域的变量的函数

    简单说:闭包就是一个函数,这个函数能够访问其他函数的作用域中的变量

    function outer() {
    var a = '变量1'
    var inner = function () {
    console.info(a)
    }
    return inner // inner 就是一个闭包函数,因为他能够访问到outer函数的作用域
    }

    
    匿名函数与闭包的关系,闭包是站在<b>作用域</b>的角度上来定义的
    因为 inner 访问到 outer 作用域的变量,所以inner就是一个闭包函数。
    虽然定义很简单,但是有很多坑点,比如this指向、变量的作用域,不注意的话可能就造成 <b>内存泄露</b>。
    
    为什么闭包函数能够访问其他函数的作用域 ?
    从堆与栈的角度看待JS函数

    栈内存:基本数据类型( Number 、Boolean、Undefined、String、Null)
    堆内存:对象类型的变量

    var num = 10 //num是基本数据类型
    Var num2 = {name:'Jack'} //num2是对象

    >
    >
    >![](https://img2018.cnblogs.com/blog/1481359/202002/1481359-20200223200737176-1196446462.png)
    >当num2 = {name:'Tom'} 时,堆 里边就有一个新的对象{name:'Tom'},原来的{name:'Jack'} 就会被程序垃圾引擎回收掉,节约内存空间
    >
    >######JS函数
        function fn() {
                    var a = 1
                    var b = 2
                    console.log(a)
                    var p = function () {
                        console.log(b)
                    }
                    return p    
                }
                fn()
                var p2 = new fn()
                p2()
    ><b>当程序在调用某个函数时,做了以下的工作:准备执行环境,初始函数作用域链和arguments参数对象</b>
    >>注:arguments参数对象:是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。
    >>   此对象包含传递给函数的每个参数,第一个参数在索引0处
    >
    >当程序执行完var p2 = new fn(),其实fn的执行环境并没有被销毁,因为他里面的变量a仍然被被inner的函数作用域链所引用
    >
    >当程序执行完p(), 这时候,fn和p的执行环境才会被销毁调;
    >
    >由于闭包会携带包含它的函数的作用域,因为会比其他函数占用更多内容,过度使用闭包,会导致内存占用过多
    >
    
    ####注意的是闭包看似简单,但是又有很多的细节与坑点
    #####坑点一:引用的变量可能发生变化
    
    
        function fn() {
              var arr= [];
              for (var i = 0; i<10; i++){
                arr.[i] = function () {
                    console.log(i)
                    }
            }
             return arr
        }
    
    >我们认为误认为 输出的结果为0,1,2...,10,但并不是
    >因为每个闭包函数访问变量i是fn执行环境下的变量i,
    >随着循环的结束,i已经变成10了,所以执行每个闭包函数,结果打印10, 10, ..., 10
    #####解决办法:
        function fn() {
              var arr= [];
              for (var i = 0; i<10; i++){
                arr.[i] = function (num) {
                    return function(){
                         console.log(i)
                        }
                    }(i)
            }
             return arr
        }
    
    #####坑点二:this指向问题
    
        var object = {
             name: ''object",
             getName: function() {
                return function() {
                     console.info(this.name)
                }
            }
        }
        object.getName()()    // underfined
        // 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向windows
    
    #####坑点三:内存泄露问题
    
        function  showId() {
            var el = document.getElementById("app")
            el.onclick = function(){
              aler(el.id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
            }
        }
        
            // 改成下面
            function  showId() {
            var el = document.getElementById("app")
            var id  = el.id
            el.onclick = function(){
              aler(id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
            }
            el = null    // 主动释放el
        }
  • 相关阅读:
    GNU风格 汇编语法总结(转)
    CPSR和SPSR(转)
    C语言调用汇编实现字符串对换
    ubuntu如何跑arm程序
    Shell编程之函数调用
    arm汇编--ubuntu12.04 安装arm-linux交叉编译环境
    linux关于bashrc与profile的区别(转)
    Shell如何传递字符串
    打印指针指向的地址值
    在CentOS 6.4中支持exfat格式的U盘
  • 原文地址:https://www.cnblogs.com/pp-yang/p/12354239.html
Copyright © 2011-2022 走看看