zoukankan      html  css  js  c++  java
  • javascript中的闭包

    一、什么是闭包

      函数在定义时的 词法作用域 以外的地方被调用,就会产生闭包。

    二、产生闭包的原因

      都是因为 词法作用域 造成的。无论通过何种手段将内部函数传递到所在的词法作用域以外,它都会持有对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包,且使得该作用域能够一直存活,没办法进行垃圾回收。

     function foo(){
                let a = 1;
                function bar(){
                    console.log(a);
                }
                return bar;
            }
    
            const f = foo();
            //这就是闭包(原本bar()是存在foo()作用域里的,外部不能返回,但现在foo()外部也能访问)
            f();    //1
    
    
            for(var i=0;i<5;i++){
                //与我们设想结果不一样的原因: 所有的回调函数依然是在循环结束后才会被执行,因此会每次输出一个5 出来。
                setTimeout(()=> console.log(i),0);  //5 5 5 5 5 
            }
    
            //所以,上面的代码等价于
            for(var i=0;i<5;i++){}
            setTimeout(()=> console.log(i),0);        //5
            setTimeout(()=> console.log(i),0);        //5
            setTimeout(()=> console.log(i),0);        //5
            setTimeout(()=> console.log(i),0);        //5
            setTimeout(()=> console.log(i),0);        //5
    
            //解决方法1:运用IIFE创建闭包作用域
            for(var i=0;i<5;i++){
                (function(j){
                    setTimeout(()=> console.log(j),0);  //0 1 2 3 4
                })(i);
            }
            //解决方法2:使用let,生成块作用域
            for(let i=0;i<5;i++){
                setTimeout(()=> console.log(i),0);  //0 1 2 3 4
            }

    三、应用

    1、在定时器、事件监听器、Ajax请求、跨窗口通信、Web Workers或者任何其他的异步(或者同步)任务中,只要使 用了回调函数,实际上就是在使用闭包!

    2、模块

    function foo(){
                let a = 1;
                function bar(){
                    console.log('foo bar');
                }
                return {a, bar};    //返回含有对内部函数的引用的对象
            }
    
            //创建模块实例
            const f = foo();
            f.bar();    //foo bar      这就是闭包
    //模块管理器的原理(单例模式)
            var MyModules = (function Manager(){
                var modules = {};
                function define(name, deps, impl){
                    for(var i=0; i<deps.length; i++){
                        deps[i] = modules[deps[i]];
                    }
                    modules[name] = impl.apply(impl, deps);
                }
                function get(name){
                    return modules[name];
                }
                return{
                    define: define,
                    get: get
                };
            })();
    
            MyModules.define('bar',[],function(){
                function hello(who){
                    return "Let me instroduce " + who;
                }
                return {
                    hello: hello
                };
            });
            
            MyModules.define("foo",["bar"],function(bar){
                var hungry = "hippo";
                function awesome(){
                    console.log(bar.hello(hungry).toUpperCase());
                }
                return {
                    awesome: awesome
                };
            });
            
            var bar = MyModules.get("bar");
            var foo = MyModules.get("foo");
            console.log(bar.hello("hippo"));    //Let me instroduce hippo
            foo.awesome();      //LET ME INSTRODUCE HIPPO

      ES6中的模块(一个文件,一个模块)

     //bar.js源码
    function hello(who){
        return "Let me instroduce " + who;
    }
    export {hello};
    
     //foo.js源码
    import {hello} from "./bar.js";
    
    let hungry = "hippo";
    function awesome(){
        console.log(hello(hungry).toUpperCase());
    }
    export {awesome};
    
    html.html源码
    <html>
    
    <head></head>
    
    <body>
    
        
    
        <script type="module">
    
           import {awesome} from "./js/foo.js";
           import {hello} from "./js/bar.js";
    
          
           console.log(hello("rhino"));        //Let me instroduce rhino
           awesome();        //LET ME INSTRODUCE HIPPO
    
        </script>
    
    </body>
    
    </html>
  • 相关阅读:
    mysql查看所有触发器以及存储过程等操作集合【转】
    Hutool之Http工具类使用
    SpringCloud之Sentinel
    SpringCloud之Gateway
    com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
    [AWS DA Guru] SQS
    [AWS DA Guru] Kinesis
    [AWS DA Guru] SNS & SES
    [Typescript] Prevent Type Widening of Object Literals with TypeScript's const Assertions
    [AWS] Updating Elastic Beans Talks & RDS
  • 原文地址:https://www.cnblogs.com/zxn-114477/p/14443183.html
Copyright © 2011-2022 走看看