• 闭包_理解闭包


    闭包允许函数访问并操作函数外部的变量。只要变量或函数存在声明时的作用域内,闭包即可使用函数能够访问这些变量或函数。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script src="../unitl/test.js"></script>
        <style>
            #results li.pass {color:green;}
            #results li.fail {color:red;}
        </style>
    
    
    </head>
    
    <body>
        <ul id="results"></ul>
    </body>
    <script>
        //在全局作用域定义一个变量
        var outerValue = "ninja";
    
        function outerFunction() {
    
            //在全局作用域中声明函数
            assert(outerValue==="ninja","I can see the ninja.");
    
        }
    
        // 执行该函数
        outerFunction();
    </script>
    </html>
    

    在本例中,在统一作用域中声明了变量outerValue及外部函数outerFunction-- 本例中,是全局作用域,然后,执行外部函数outerFunction。

    如上图,在函数可以“看见”并访问变量outerValue。我们可能写过上百次这样的代码,但是却没有意识到起始我们正在创建一个闭包!
    因为外部变量outerValue和外部函数outerFunction都是在全局作用域中声明的,该作用域(实际上实际上就是一个闭包)从为消失(只要应用属于运行状态)。这也不足为奇了。该函数可以访问到外部变量。因为他仍然在作用域内并且是可见的。
    虽然闭包存在,但是闭包的优势仍然不明显。让我们在接下来的例子中加点料。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script src="../unitl/test.js"></script>
        <style>
            #results li.pass {color:green;}
            #results li.fail {color:red;}
        </style>
    
    
    </head>
    
    <body>
        <ul id="results"></ul>
    </body>
    <script>
        //在全局作用域定义一个变量
        var outerValue = "samurai";
    
        var later;
    
        function outerFunction() {
    
            //在全局作用域中声明函数
    
            var innerValue = "ninja";
    
    
    
            function innerFunction() {
                
                //在outerFunction函数中声明一个内部函数,声明该内部函数时,innerValue是在内部函数的作用域内的。
                assert(outerValue==="samurai","I can see the samurai");
                assert(innerValue==="ninja","I can see the ninja");
    
    
            }
    
            //将内部函数innerFunction的引用存储在变量later上,因为later在全局作用域内的,所以我们可以对她进行调用。
            later = innerFunction;
    
        }
    
        // 调用outerFunction函数内,创建内部函数innerFunction,并将内部函数赋值给later。
        outerFunction();
    
        //通过later调用内部函数。我们不能直接调用内部函数,因为他有作用域(和innerValue一起)被限制在外部函数outerFunction之内。
        later();
    
    
    
       
        
    </script>
    </html>      
    

    仔细研究一下内部函数innerFunction中的代码,看看我们能否预测会发生什么。

    • 第一个断言肯定会通过,因为外部变量outerValue在全局作用域内,并且在任何地方都可见。但是第二个断言呢?
    • 外部函数执行后,我们通过将内部函数的引用赋值给全局变量later,再通过later调用内部函数。
    • 当内部函数执行时,外部函数的作用域已经不存在了,并且在通过later调用内部函数时,外部函数的作用域已不可见了。
    • 所以我们可以很好的预见断言失败,因为内部变量innerValue肯定是undefined,对吗?
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>另一个闭包的例子</title>
        <script src="../unitl/test.js"></script>
        <style>
            #results li.pass {color:green;}
            #results li.fail {color:red;}
        </style>
    
    
    </head>
    
    <body>
        <ul id="results"></ul>
    </body>
    <script>
        //在全局作用域定义一个变量
        var outerValue = "samurai";
    
        var later;
    
        function outerFunction() {
    
            //在全局作用域中声明函数
    
            var innerValue = "ninja";
    
    
    
            function innerFunction() {
                
                //在outerFunction函数中声明一个内部函数,声明该内部函数时,innerValue是在内部函数的作用域内的。
                assert(outerValue==="samurai","I can see the samurai");
                assert(innerValue==="ninja","I can see the ninja");
    
    
            }
    
            //将内部函数innerFunction的引用存储在变量later上,因为later在全局作用域内的,所以我们可以对她进行调用。![](https://img2020.cnblogs.com/blog/1072158/202012/1072158-20201222143249993-1340542549.jpg)
    
    
            later = innerFunction;
    
        }
    
        // 调用outerFunction函数内,创建内部函数innerFunction,并将内部函数赋值给later。
        outerFunction();
    
        //通过later调用内部函数。我们不能直接调用内部函数,因为他有作用域(和innerValue一起)被限制在外部函数outerFunction之内。
        later();
    
    
    
       
        
    </script>
    </html>
    

    但是,当我们执行完测试时,我们看到如下图所示。

    是什么魔法使得内部函数的作用域消失之后再执行内部函数时,其内部变量仍然存在呢?
    当在外部函数中声明内部函数时,不仅定义了函数的声明,而且还创建了一个闭包。该闭包不仅包含了函数的声明,还包含了在函数声明时该作用域中的所有变量。
    当最终执行内部函数时,尽管声明时的作用域已经消失了,但是通过闭包,仍然能够访问该作用域。如下图所示。


    正如上图一样,只要内部函数一直存在,内部函数的闭包就一直保存该函数的作用域中的变量。
    这就是闭包。闭包创建了被定义时的作用域内的变量和函数的安全域,因为函数获取执行时所需内容。该安全域与函数本身一起包含了函数的变量。
    虽然这些结构不容易看见(没有包含这么多信息的闭包对象可以进行观察),存储和引用这些信息会直接影响性能。谨记每一个通过闭包访问变量的函数都具有一个作用域链,作用域链包含闭包的所有信息,这一点非常重要。因此,虽然闭包是非常有用的,但不能过度使用。使用闭包时,所有的信息都会存储在内存中,直到JavaScript引擎确保这些信息不在使用(可以安全地进行垃圾回收)或页面卸载时,才会清理这些信息。

  • 相关阅读:
    Asp Net Core Fro MongoDB Part1
    Word 离线发布bolg测试
    Word 2016问题导致无法创建其他博客账号
    字符集工具
    人工智能笔摘
    js数组去重
    ##react-native学习笔记(windows android)##第4天,分析下目录结构
    ##react-native学习笔记(windows android)##第3天,解决白屏闪退问题
    ##react-native学习笔记(windows android)##第2天, Hello world !
    ##react-native学习笔记(windows android)##第1天,搭建开发环境
  • 原文地址:https://www.cnblogs.com/jamal/p/14173482.html
Copyright © 2020-2023  润新知