美文网首页
javascript深入理解系列——(六)闭包

javascript深入理解系列——(六)闭包

作者: 悦者生存 | 来源:发表于2018-09-08 22:02 被阅读9次

javascript深入理解系列文章网址
https://www.jianshu.com/p/451eed9094f5

闭包真是面试80%会问到的问题

闭包的概念

简单来说能够读取其他函数内部变量的函数

怎么来理解这句话呢,我们都知道函数内可以读取外部的变量,但是函数外无法读取函数内部的变量
那么怎么才能做到读取函数内部的变量呢,我们可以在函数内部再定义一个函数,用这个函数读取函数内部的变量,然后最后返回里面这个函数执行的结果,我们就可以得到函数内部的变量了

        function Out(){
            var a=678;
            function In(){
                console.log(a);
            }
            return In;
        }
        var result=Out();
        result();//678

那么闭包有什么用呢

1.可以读取函数内部的变量
2.让这些变量的值始终保持在内存中,不会在调用后被自动清除。

那我们什么时候用到闭包的?

1、通过闭包来封装私有方法

学过java的同学都知道,java可以在类里面写私有变量和方法,外面无法调用,其实在js里面也能实现的,怎么实现那就需要闭包了

var fn=(function(){
        var counter=0;
        function getValue(val){
            counter+=val;
        }
        return {
            increment:function(){
                getValue(1);
            },
            decrement:function(){
                getValue(-1);
            },
            value:function(){
                return counter;
            }
        }
    })();
    console.log(fn.value());//输出0
    fn.increment();
    console.log(fn.value());//输出1

学过java的同学看到这个是不是很熟悉,像不像java里的面向对象,这里面的increment,decrement,value就相当于闭包,我们可以封装私有变量counter,然后通过闭包对齐操作

解决循环错误的问题

我们先来看代码

<body>
        <button>0</button>
        <button>1</button>
        <button>2</button>
    </body>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <script>
        
        for(var i=0;i<$("button").length;i++){
            $("button").eq(i).click(function(){
                console.log(i);//输出结果总是3
            });
        }
    </script>

上面我们定义了三个按钮,原计划点击相应的按钮,打印相应的文字,但是我们像如上的写法输出后每次的结果都是3,为什么呢,因为我们定义的这些函数不是立即执行函数,而是点击的时候才会执行,可是当我们点击的时候,循环已经结束,i为3,所以我们输出的值都为3。如何解决呢,这就要使用闭包了

<body>
        <button>1</button>
        <button>2</button>
        <button>3</button>
    </body>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <script>
        
        for(var i=0;i<$("button").length;i++){
            (function(val){
                $("button").eq(val).click(function(){
                console.log(val);
                });
            })(i);
            
        }
    </script>

当for循环的时候,自执行函数就会执行

 $("button").eq(val).click(function(){
                console.log(val);
                });

而val值是从外面传过来,里面的闭包就会记住每一次的值,存在内存中,每一次的

 $("button").eq(val).click(function(){
                console.log(val);
                });

都是互相独立的,所以每一次输出的值互不相同

let和闭包的关系

同样是这个问题

<body>
        <button>0</button>
        <button>1</button>
        <button>2</button>
    </body>
 <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
 <script>
        for(var i=0;i<$("button").length;i++){
            $("button").eq(i).click(function(){
                console.log(i);//输出结果总是3
            });
        }
    </script>

之所以输出结果总是为3,是因为js只有全局作用域和函数级作用域,当点击的时候就会调用全局作用域i,i为3,所以我们可以使用es6的语法let去添加块级作用域

<body>
        <button>0</button>
        <button>1</button>
        <button>2</button>
    </body>
 <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
 <script>
        for(let i=0;i<$("button").length;i++){
            $("button").eq(i).click(function(){
                console.log(i);
            });
        }
    </script>

只要把var改成let就可以,就有了块级作用域,每次点击button的时候都访问其内部的i变量,也就可以解决上面的问题

闭包的优缺点

优点:加强封装性,可以达到对变量的保护作用

缺点:1由于闭包内部变量优先级高于外部变量,所以多查找作用域链中的一个层次,就会在一定程度上影响查找速度
2.内存的浪费
如何避免浪费使父级函数=null;

参考
https://juejin.im/post/5aa90e5ef265da239f0713a1#heading-5

https://wangdoc.com/javascript/basic/index.html

相关文章

网友评论

      本文标题:javascript深入理解系列——(六)闭包

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