javascript学习十三:闭包

函数的执行顺序

    fn1();
    //不会报错,对于通过function fn()这种写法来定义的函数,永远都会被最先初始化
    function fn1() {
        alert("fn1");
    }

    fn2();
    //使用如下方式定义函数,不会被先执行,如果在之前调用该函数就会报错
    /** * 以下函数的定义方式是先在内存中创建了一块区域,之后通过一个fn2的变量 * 指向这块区域,这块区域的函数开始是没有名称的 ,这种函数就叫做匿名函数 */
    var fn2 = function() {
        alert("fn2");
    }   

函数的作用域链

    /** * 在js中当进行函数的调用,会为每一个函数增加一个属性SCOPE,通过这个属性来指向一块内存 * 这块内存中包含有所有的上下文使用的变量,当在某个函数中调用了新函数之后,新函数依然 * 会有一个作用域来执行原有的函数的SCOPE和自己新增加的SCOPE,这样就形成一个链式结构 * 这就是js中的作用域链 */
    var color = "red";

    var showColor = function() {
        alert(this.color);
    }

    function changeColor() {
        var anotherColor = "blue";
        function swapColor() {
            var tempColor = anotherColor;
            anotherColor = color;
            color = tempColor;
        }
        swapColor();
    }

    changeColor();

    showColor();//blue

闭包的定义

js的函数能返回一个函数帮助我们扩大函数的作用域,这种方式就叫闭包。
使用闭包虽然可以延长作用域,但是会占用个更多的内存,一般非特殊情况不要使用闭包

    /** * 通过以下操作带来最大的好处是,compareObjectFunction的作用域变大了 * 当compareObjectFunction结束之后,prop这个变量依然存在 */
    function compareObjectFunction(prop) {
        //匿名函数
        return function(obj1,obj2) {
            if(obj1[prop]>obj2[prop]) return 1;
            else if(obj1[prop]<obj2[prop]) return -1;
            else return 0;
        }
    }
    var o1 = {name:"Leon",age:23};
    var o2 = {name:"Ada",age:28};
    //此时就是基于name来进行比较
    /* * 在java或者c++中,以下代码执行完成之后,需要进行内存的释放 * 此时对于java和c++这些静态语言而言,prop会被释放 * 但是在js中,这个作用域却被放大了 */
    var compare = compareObjectFunction("age");
    //此时就比较了o1和o2
    /* * 在js中,prop在这里依然可以被访问,这种通过返回函数来扩大函数的作用域的方法 * 就是闭包 */
    var rel = compare(o1,o2);
    alert(rel);//-1

闭包的变量问题

    function fn1() {
        //创建了一个数组
        var fns = new Array();
        //i这个变量是保存在fn1这个作用域中的
        for(var i=0;i<10;i++) {
            //数组中放的值是一组函数
            fns[i] = function() {
                return i;
            }
        }
        return fns;
    }

    var fs = fn1();
    for(var i=0;i<fs.length;i++) {
        //此时通过闭包来调用所有函数,当输出i的时候会去上一级的作用域中查找
        //这个时候i的值已经10,所以连续输出了10个10
        document.write(fs[i]()+"<br/>");
    }

解决方法:

    function fn1() {
        //创建了一个数组
        var fns = new Array();
        //i这个变量是保存在fn1这个作用域中的
        for(var i=0;i<10;i++) {
            //num这个变量是保存在fns这个tf这个作用域,每一个闭包的num都是不一样
            //所以此时所消耗的内存特别的大
            var tf = function(num) {
                fns[num] = function() {
                    return num;
                }
            }
            tf(i);
        }
        return fns;
    }

    var fs = fn1();
    for(var i=0;i<fs.length;i++) {
        //每一个fs都是在不同作用域链中,num也是保存在不同的作用域中,所以输出0-9
        document.write(fs[i]()+"<br/>");
    }

闭包的this的问题

var name = "window";
    var person = {
        name:"zhangsan",
        age:23,
        say:function() {
            return function() {
                return this.name;
            }
        }
    }
    /* * 当完成person.say()之后,这个函数就调用结束了,在这个函数调用结束之前 * this是指向person,但是在调用匿名函数的时候,this就指向window,所以 * 得到的结果是window * */
    alert(person.say()());

解决方法

var name = "window";
    var person = {
        name:"zhangsan",
        age:23,
        say:function() {
            //that就指向person
            var that = this;
            return function() {
                return that.name;
            }
        }
    }
    /* * 此时that是指向person的,所以调用that.name就是person中name * */
    alert(person.say()());

使用闭包解决js中没有块作用域的问题

  1. js中没有块作用域
    for(var i=0;i<10;i++) {

    }
    //在js中没有块作用域,不管是使用循环还是判断之后,这个变量会一直存在
    /* * 所以当在全局使用某个变量进行循环或者判断之后,这个变量可能会影响 * 到函数中的变量,所以在特殊情况不要使用全局变量,而且使用全局变量 * 在作用域链的最上层,访问是最慢的 */
    var i;//此时会认为是无效语句,除非使用var i = 0;
    alert(i);
  1. 解决方法:
    /* * 在一个团队进行开发时,可能会涉及到定义同名的全局变量,所以在开发中 * 一定养成如下习惯,将全局变量的代码放到一个匿名函数,并且马上调用 * 匿名函数,这样也可以执行全局变量的代码,但是这些变量就被控制在开发 * 人员想要控制的作用域中了 */
    //在function的{}后不能直接调用,一定要加上括号
    // function(){
        // for(var i=0;i<10;i++) {
// 
        // } 
    // }();
    (function(){
        for(var i=0;i<10;i++) {

        }   
    })();

    function fn() {
        alert(i);
    }
    fn();//此时会出错,因为没有i

私有变量的定义

    function Person(name) {
        /** * 此时就没有办法直接访问name这个属性,因为没有this.name * 要访问name只能通过this.getName,this.setName * 但是使用这种方式创建私有变量带来的问题是,每个对象都存储大量的函数 * 解决的办法是通过静态私有变量来解决 */
        this.setName = function(value) {
            name = value;
        }
        this.getName = function() {
            return name;
        }
    }

    var p = new Person("aa");
    alert(p.getName());
    p.setName("bb");
    alert(p.getName());

这种方式创建私有变量带来的问题是,每个对象都存储大量的函数。解决的办法是通过静态私有变量来解决。

    var Person;
    (function(){
        //name正在函数结束之后就消失,在外面是无法引用的
        var name = "";
        Person = function(value){
            name = value;
        }
        Person.prototype.setName = function(value) {
            name = value;
        }
        Person.prototype.getName = function() {
            return name;
        }
    })();

    var p1 = new Person("aa");
    alert(p1.getName());
    p1.setName("bb");
    alert(p1.getName());

你可能感兴趣的:(JavaScript,闭包)