函数表达式---闭包

来源:互联网 发布:java 整型 编辑:程序博客网 时间:2024/06/05 21:02

闭包:

有权访问另一个函数作用域内变量的函数。常见的方式就是在一个函数的内部创建另外一个函数。
        function a(){            var color = "red";            function b(){                alert(color);            }            b();        }        a();        a内的b可以访问a的内部变量color;
注意:由于闭包会携带包含他的函数的作用域(例如闭包携带包含b的a这个函数的作用域),所以比其他的函数占更多的内存。过度使用闭包会导致内存占用的过多。谨慎使用闭包。

1.闭包和变量

副作用:闭包只能取到包含函数中任何变量的的最后一个值。
        function a(){            var arr = [];            for(var i = 0;i < 10;i++){                arr[i] = function(){                    return i;                };            }            return arr;        }        console.log(a()[0]())//10        console.log(a()[3]())//10        console.log(a()[8]())//10
    上面的这个闭包内的函数,看起来是0位置的函数返回0,以此类推,其实不是。每一个函数的作用域中都保存着a()函数的活动对象,他们引用的是同一个变量i,当a()运行结束,i返回为10,此时每一个函数引用的变量i是同一个变量对象,所以每一个函数的内部i都是10.
可以利用下面的方式实现:        function a(){            var arr = [];            for(var i = 0;i < 10;i++){                arr[i] = function(num){                    return function(){                        return num                    };                }(i);            }            return arr;        }        console.log(a()[0]())//0        console.log(a()[3]())//3        console.log(a()[8]())//8
    我们没有直接将闭包赋值给数组,而是定义了一个匿名函数,并将立即执行该函数的结果赋值给数组。(立即执行函数(function(num))(i)中的第二个()为调用函数,i为传入的参数)。这样就将不同的i赋值给了num,而在匿名函数的内部有返回一个访问num的闭包,这样一来数组arr中的每一个元素所对应的的函数都有自己的num变量。

2.关于this

    this是函数运行的环境所决定的,在全局调用函数,this就是window。函数被当做某个对象的方法调用时,this就是这个对象。    不过,匿名函数的执行环境具有全局性,因此this对象通常指向window。
        var name = "this is window";        var obj = {            name:"opbject",            say:function(){                return function(){                    alert(this.name);                };            }        };        obj.say()();//"this is window"
    这是因为obj.say()其实是返回了匿名函数:            function(){                alert(this.name);            };    然后又在全局环境下调用了,所以this指向window。
    也可以让闭包访问obj对象        var name = "this is window";        var obj = {            name:"opbject",            color:"red",            say:function(){                var that = this;                return function(){                    alert(that.name);                };            }        };        obj.say()();//"opbject"        因为that指向的就是obj。
    在某些特殊的环境下this会发生改变。        var name = "this is window";        var obj = {            name:"opbject",            say:function(){                             alert(this.name);            }        };        obj.say();//"opbject"        (obj.say)();//"opbject"
    因为this.name就是obj.name    (obj.say = obj.say)()//"this is window"    这是因为复制了函数,函数与obj没有关系了,只是函数,在全局环境下调用,所以this=window

3.内存泄露

如果闭包的作用域链保存一个HTML元素,就会造成内存泄漏。
    function a(){        var b = document.getElementById("hcd"); //b用完之后一直驻留在内存        b.click = function(){            alert(b.id)        }    }
如果想回收内存,那么引用数需要可以减少为0,但是b在闭包内至少被引用了1回,导致内存无法回收。
    function a(){            var b = document.getElementById("hcd");            var id = b.id;            b.click = function(){                alert(id)            }            b = null;        }
    这样就可以了,因为闭包会引用包含函数在内的活动对象,而变量b是活动对象的一个属性,所以任然会有一个引用。    所以用必要将b=null
阅读全文
0 0