js_闭包和闭包应用场景

理解作用域链是理解闭包的基础:js_作用域链
闭包的定义?
在 JavaScript 中,根据词法作用域的规则,内部函数总是可以访问其外部函数中声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合称为闭包。比如外部函数是 foo,那么这些变量的集合就称为 foo 函数的闭包。
什么是词法作用域?
词法作用域就是指作用域是由代码中函数声明的位置来决定的,所以词法作用域是静态的作用域,通过它就能够预测代码在执行过程中如何查找标识符。
那这些闭包是如何使用的呢?
当执行到 bar.setName 方法中的myName = "极客邦"这句代码时,JavaScript 引擎会沿着“当前执行上下文–>foo 函数闭包–> 全局执行上下文”的顺序来查找 myName 变量,你可以参考下面的调用栈状态图:
js_闭包和闭包应用场景_第1张图片

如何产生闭包?
当函数嵌套时,内层函数引用了外层函数作用域下的变量,并且内层函数在全局作用域下可访问时,就形成了闭包。

产生闭包的条件?函数嵌套且内部函数引用了外部函数的数据(变量/函数),执行内部函数定义时就会产生闭包(不用调用内部函数,但是外部函数必须调用才会产生闭包)。
思考题:
下面代码有闭包吗?

var bar = {
    myName:"time.geekbang.com",
    printName: function () {
        console.log(myName)
    }    
}
function foo() {
    let myName = "极客时间"
    return bar.printName
}
let myName = "极客邦"
let _printName = foo()
_printName()
bar.printName()

答案是没有闭包产生且两次打印都为‘极客邦’,详见:极客时间——作用域链和闭包
常见的闭包:
1,将函数作为另一个函数的返回值(fn外面的作用域可以访问fn内部的局部变量,访问但不可以修改)将函数作为实参传递给另一个函数调用。

        function fn(){
            var num=10;
            function fun(){
                console.log(num);
            }
            return fun;
        }
        var f=fn();
        //类似于f=function fun(){
        //    console.log(num);
        //}
        f();
或者直接返回一个匿名函数(高阶函数)
        function fn(){
            var num=10;
            return function(){//匿名函数
                console.log(num);
            }
        }
        var f=fn();
        f();

闭包的应用场景:
1>循环注册点击事件。
点击li输出当前li的索引号

<body>
    <ul class="nav">
        <li>榴莲</li>
        <li>臭豆腐</li>
        <li>鲱鱼罐头</li>
        <li>大猪蹄子</li>
    </ul>
<script>
        //1,利用动态添加属性的方式
        var lis=document.querySelector('.nav').querySelectorAll('li');
        for(var i=0;i<lis.length;i++){
            lis[i].index=i;
            lis[i].onclick=function(){
                console.log(this.index);
            }
        }
        //利用闭包的方式得到当前小li的索引号
        for(var i=0;i<lis.length;i++){
            (function(i){
                lis[i].onclick=function(){
                    console.log(i);
                }
            })(i);
        }     
    </script>
</body>

2>循环中的setTimeout()

<body>
    <ul class="nav">
        <li>榴莲</li>
        <li>臭豆腐</li>
        <li>鲱鱼罐头</li>
        <li>大猪蹄子</li>
    </ul>
    <script>
        //闭包应用:3s之后,打印所有li元素的内容
        var lis =document.querySelector('.nav').querySelectorAll('li');
        for(var i=0;i<lis.length;i++){
            (function(j){
                setTimeout(function(){
                    console.log(lis[j].innerHTML);
                },3000)

            })(i);
        }       
    </script>
</body>

闭包的优缺点:
优点:延申了变量的作用范围,(以前,函数内的局部变量仅限于本函数内使用,以外不能使用,但是闭包可以实现在函数作用域外访问函数内部的局部变量。num这种局部变量在函数执行完就会销毁,但是有了闭包以后,函数执行完不会立即销毁,下面还有函数调用要访问它)
缺点:函数执行完后,函数内的局部变量没有释放,占用内存时间会变长,容易造成内存泄露。

你可能感兴趣的:(JavaScript,前端,javascript,javascript)