• 闭包


    闭包初识

      在MDN中闭包的定义为:可以访问自由变量的函数。(所以我们可以将所有的函数看做是闭包)

      在我们平时的开发使用的我们可以对闭包定义为:可以在函数本身作用域以外的地方被调用。

      首先我们应该先了解一个概念,JS的作用域是静态的,不管函数以哪种方式被调用都只访问申明函数时的作用域内的变量

          先看下面的一个小例子:

    var a = "outer";
    function print(){
        console.log(a);
    }
    print();
    //毫无疑问打印-->outer
    var a = "outer";
    function print(){
        console.log(a)
    }
    function log(){
        var a = "inner";
        print();
    }
    log();
    //仍然会打印
    -->outer
    var a = "outer";
    function print(){
        var a = "inner";
        return function(){
            console.log(a);
        }
    }
    var log = print();
    log();
    //打印-->inner

      通过红色的定义我们已经知道函数在调用时,会访问声明函数时的作用域内的变量,所以我们第二个函数会输出outer第三个函数会输出inner。

      首先说明第三个函数已经构造除了一个最简单的闭包。我们知道函数print形成了一个独立的块级作用域,里面的变量只能在函数内部使用,并且在正常的情况下,一旦函数调用完成就会回收里面声明的变量,我们在外层作用域不能访问到,但是在实际上我们在第三个函数中通过log函数额调用仍然输出了inner,这已经违背了我们一般情况,这种特殊的情况我们就称为闭包,更加通俗但不准备的定义--可以外层作用域访问到内层作用域的变量,着就是闭包。

    闭包使用

      闭包即一个封闭的空间,通过闭包我们形成一个独立的作用域,可以减少变量名称之间的污染。能形成独立作用域的我们最常见的就是函数,所以闭包和函数就是树和叶一样,其实是不分彼此的。而我们经常使用的一个闭包方式就是匿名函数自执行--(function(){--statement--}())

      闭包的一个好处就是可以减少变量的污染,这个是显而易见的:

    (function(){
        var name = "zt";
        console.log(name)
    }())
    (function(){
        var name = "xjj";
        console.log(name);
    }())

      我们对某一个模块的操作不会影响到另一个模块。

      在我们平时的开发中同时会通过三种方式来使用闭包:

      1.参数传递

      2.return 一个基本类型或者对象

      3.对对象的属性进行扩展

      我们先看一个经典的闭包问题:

    for(var i=0;i<5;i++){
        setTimeout(function(){
            console.log(i);
        },0)
    }

      我们想打印出每次循环的i的值,而上面的这段代码显然是不能达到我们的预期的效果的,因为JS是一种运行在浏览器/node环境中一种单线程语言,只有主线程执行完毕之后,才会去执行消息队列中的语句,所以上面的代码我们可以理解为每一次的循环都会创建一个函数,这个函数的功能的输出i的值,只有循环执行完成以后才会调用函数,但是当调用函数的时候i的值已经变成了5,所以会输出5个5。

      为了达到我们预期的效果我们可以使用闭包来完成:

    for(var i=0;i<5;i++){
        (function(i){
            setTimeout(function(){
                console.log(i)
            },0)
        }(i))
    }

      此时我们预期的效果已经实现-->0,1,2,3,4

      每次循环创建的函数不再去访问我们的变量i而是去访问我们的参数i,每一个函数的参数都是我们当前循环的变量i的值,所以达到了我们预期的效果。

      另一种我们使用的闭包的方式为 return 一个对象

    var person = function(){
        var current = new Date();
        var year = current.getFullYear();
        var age = year - 1993;
        return {
            name:"zt",
            age:age
        }
    }();

      通过我们完成了一个操作-->声明一个对象var person = {name:"zt",age:age},通过person.age属性我们可以访问到我们函数内部的变量age的值,同时减轻了变量的污染

      最重要的一种使用闭包的方式为,对某个对象进行属性扩展

    var person = {};
    (function(p){
        function say(){
            console.log("i can say");
        }
        function sport(){
            console.log("i like sport");
        }
        p.say = say;
        p.sport = sport;
    }(person))

      通过这种方式我们为person对象扩展了两个方法,我们经常使用的JQ插件就是通过这种方式来进行扩展的。

  • 相关阅读:
    《第三周作业》——第四小组
    《UML与设计原则》--第四小组
    《我与计算机》——第四小组
    PSP数据比较(四则运算)——计应193第6组栗亚文
    个人工作流程(地铁收费系统)——计应193第6组张淑雅
    设计模式学习总结
    行为型模式总结
    UML第二部分和创建型模式的总结(二)
    UML第二部分和创建型模式的总结
    UML第一部分和设计模式原则的总结
  • 原文地址:https://www.cnblogs.com/shinhwazt/p/5887036.html
Copyright © 2020-2023  润新知