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>

 

posted @ 2021-02-25 17:42  拉布拉多~  阅读(64)  评论(0编辑  收藏  举报