美文网首页
深入理解闭包

深入理解闭包

作者: 每日log | 来源:发表于2020-12-29 16:51 被阅读0次

    01 什么是闭包

    闭包指有权访问另一个函数作用域中变量的函数
    其实,闭包就是一个内部函数

    1.举例
    function outer() {
        let a = 5 // outer中的变量
        function inner() {
            console.log(a) //5
        }
        inner()
    }
    outer()
    //a是outer中的变量, inner函数的作用域访问了另一个函数即outer内部的变量 a
    
    2.什么是闭包函数

    函数inner就是一个闭包函数

    function outer(){
        function inner(){
        }
    }
    

    02闭包的三个可访问作用域

    1、在它自身声明之内声明的变量
    function outer() {
        function inner() {
            let a = 5 // 自身
            console.log(a) // 5
        }
        inner()
    }
    outer()
    

    当闭包函数inner被调用的时候,控制台会输出5
    闭包函数可以访问所有在其声明内部声明的变量

    2、对全部变量的访问
    let b = 'global' // 全局变量
    function outer() {
        function inner() {
            let a = 5
            console.log(b) // global
        }
        inner()
    }
    outer()
    

    闭包能访问全局变量,此时调用闭包函数inner时,控制台会输出global

    3、访问外部函数的变量
    let b = 'global' 
    function outer() {
        let c = 'out'  // 外部变量
        function inner() {
            let a = 5
            console.log(c) // out
        }
        inner()
    }
    outer()
    

    inner函数能访问到外部函数(outer)中的变量c

    03 闭包能记住它的上下文

    let outerFn = (arg) => {
        let outer = "outer"
        let innerFn = () => {
            console.log(outer) // out
            console.log(arg)  // 5
        }
        return innerFn
    }
    outerFn(5)()
    

    当outerFn(5)被调用时,返回了innerFn 函数
    当innerFn 被返回,JavaScript引擎视innerFn为一个闭包,并相应的设置了它的作用域;arg和outer被设置到inner的作用域层级中,返回函数的引用存储到innerFn 中;
    innerFn被调用时即(outerFn(5)())就记住了arg和outer

    04 在浏览器中查看是否有闭包

    图片

    在浏览器中F12查看,closure就是闭包的意思

    05 闭包的案例

    1.点击每个li能打印出每个li的索引
    <body>
        <ul class="nav">
            <li>语文</li>
            <li>数学</li>
            <li>英语</li>
            <li>化学</li>
        </ul>
    </body>
    <script>
    
        // 创建4个立即执行函数
        var lis = document.querySelector('.nav').querySelectorAll('li')
        for (var i = 0; i < lis.length; i++) {
            (
                function (i) {
                    lis[i].onclick = function () {
                        console.log(i)
                    }
                }
            )(i)
        }
        // 立即循环函数传入的是当前循环中的i值
    </script>
    
    2. 3秒后,打印所有li的索引
    <body>
        <ul class="nav">
            <li>语文</li>
            <li>数学</li>
            <li>英语</li>
            <li>化学</li>
        </ul>
    </body>
    <script>
    
        // 闭包应用3秒后,打印所有li的索引
        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            (function (i) {
                setTimeout(function () {
                    console.log(i);
                }, 3000)
            })(i);
        }
    </script>
    

    06 闭包的经典案例题

    1、案例题1
    <script>
            var name = "The Window";
            var object = {
                name: "My Object",
                getNameFunc: function () {
                    return function () {
                        return this.name;
                    };
                }
            };
            console.log(object.getNameFunc()()) // The Window
    </script>
    

    分析 拆解

    object.getNameFunc() // 相当于
    var f = object.getNameFunc()
    f = function () {
      return this.name;
    };
    object.getNameFunc()() // 相当于
    f()
    

    this 在匿名函数里 就是f() 此时指向window

    2、案例题2
    <script>
            var name = "The Window";
            var object = {
                name: "My Object",
                getNameFunc: function () {
                    var that = this;
                    return function () {
                        return that.name;
                    };
                }
            };
            console.log(object.getNameFunc()()) // My Object
    </script>
    

    分析 拆解

    object.getNameFunc()  // 相当于
    var f = function () {
        return that.name;
    };
    object.getNameFunc()() // 相当于
    f()    
    

    var that = this的this是getNameFunc函数的调用者
    object.getNameFunc()调用了getNameFunc 即this指向 object
    f()再调用的时候,that存储的是object中的name

    07 闭包的作用

    1.延伸了变量的作用范围(可以读取函数内部的变量)
    function outer() {
        let a = 5
        function inner() {
            console.log(a) //5
        }
        return inner
    }
    let f = outer()
    f()
    

    全部作用域f()也能访问局部作用域的变量a

    2.让变量的值始终保持在内存中
    <script>
            function outer(){
                var i = 0;
                function inner(){
                    i++
                    console.log(i)
                }
                return inner
            }
            var f = outer()
            f() // 1
            f() // 2
    </script>
    

    理论上,局部变量在函数运行完是消失的,但是再次调用fn,i的值是2,说明变量保存在f这个对象上

    下一篇:【this问题】 JS中改变函数内部this的指向问题

    推荐阅读:
    1、异步编程解决方案async/await
    2、异步编程解决方案promise

    相关文章

      网友评论

          本文标题:深入理解闭包

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