zoukankan      html  css  js  c++  java
  • JavaScript闭包

    闭包:

      指有权访问另一个函数作用域中的变量的函数。
          创建闭包的常见方式,就是在一个函数内部创建另一个函数。

     1   function createComparisonFunction(propertyName){
     2             return function(obj1,obj2){//匿名函数
     3                 var value1 = obj1[propertyName];
     4                 var value2 = obj2[propertyName];
     5                 if(value1<value2){
     6                     return -1;
     7                 }else if(value1>value2){
     8                     return 1;
     9                 }else{
    10                     return 0;
    11                 }
    12             };
    13         }    

    作用域链:

      当某个函数第一次被调用时,会创建一个执行环境及相应的作用域链,并把作用域链赋值给一个特殊的内部属性。然后,使用this、arguments和其他命名参数的值来初始化函数的活动对象。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象始终处于第三位,。。。直至作为作用域链终点的全局执行环境。

     1   function compare(value1,value2){
     2             if(value1<value2){
     3                 return -1;
     4             }else if(value1>value2){
     5                 return 1;
     6             }else{
     7                 return 0;
     8             }
     9         }
    10         
    11  var result = compare(5,10);

      第一次调用compare()时,会创建一个包含this,arguments,value1和value2的活动对象。全局执行环境的变量对象(包括this,result和compare)在compare()执行环境的作用域链中处于第二位。

      一般来说,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域。但是,闭包的情况又有所不同。

      在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。在外部函数中定义的匿名函数会将外部函数的活动对象添加到它[指匿名函数]的作用域链中)

    1 var compare = createComparisonFunction('name');
    2 var result = compare({name:'Nicholas'},{name:'Greg'});

      当匿名函数从createComparisonFunction()中被返回后,它的作用域链被初始化为包含createComparisonFunction()函数的活动对象和全局变量对象。这样,匿名函数就可以访问在createComparisonFunction()中定义的所有变量。createComparisonFunction()函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数仍然在引用这个活动对象。

      就是说,当createComparisonFunction()函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中;直到匿名函数被销毁后,createComparisonFunction()的活动对象才会被销毁。例如,

    1   var compare = createComparisonFunction('name');
    2    var result = compare({name:'Nicholas'},{name:'Greg'});
    3    compare = null;//解除对匿名函数的引用,以便释放内存。

    this对象:

      this对象是在运行时基于函数的执行环境绑定的--在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。

     1     var name="the window";
     2        var object = {
     3            name:"My Object",
     4             getNameFunc:function(){
     5                 return function(){
     6                     return this.name;
     7                 };
     8             }
     9         };
    10         alert(object.getNameFunc()());//the window(非严格模式下)

      object.getNameFunc()返回一个函数,object.getNameFunc()()调用返回的函数,调用对象默认为window对象。
          把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了。

     1       var name="the window";
     2         var object = {
     3             name:"My Object",
     4             getNameFunc:function(){
     5                 var that = this;
     6                 return function(){
     7                     return that.name;
     8                 };
     9             }
    10         };
    11         alert(object.getNameFunc()());//My Object    

      定义闭包之后,闭包可以访问that变量,即使外部函数返回之后,that仍然引用这object,所以object.getNameFunc()()返回的是My Object.
            
          特殊情况,

     1     var name="the window";
     2         var object = {
     3             name:"My Object",
     4             getName:function(){
     5                 return this.name;
     6             }            
     7         };
     8         object.getName();//'My Object'
     9         (object.getName)();//'My Object',this的值不变 object.getName = (object.getName)
    10         (object.getName=object.getName)();//'the window',非严格模式下.赋值表达式的值是函数本身,this的值不能得到维持

    内存泄露:

      如果闭包的作用域链中保存着一个html元素,那么就意味着该元素将无法被销毁。

    1     function assignHandler(){
    2             var element = document.getElementById("someElement");
    3             element.onclick = function(){//闭包函数
    4                 alert(element.id);//循环引用,只要匿名函数存在,element的引用书至少是1,它所占用的内存就永远不会被回收。
    5             };            
    6         }    

    修改,

    1     function assignHandler(){
    2             var element = document.getElementById("someElement");
    3             var id = element.id;
    4             element.onclick = function(){//闭包函数
    5                 alert(id);//消除循环引用,但element仍然被间接引用着
    6             };            
    7             element = null;//接触对element的引用,回收其占用的内存
    8         }
  • 相关阅读:
    每日日报
    剑指 Offer 18. 删除链表的节点(LeetCode)
    java的访问权限
    java从键盘输入
    剑指 Offer 22. 链表中倒数第k个节点(快慢指针)(LeetCode)
    面试题 02.03. 删除中间节点(LeetCode)
    21. 合并两个有序链表(Leetcode)
    计算总线数据传输率
    时钟周期、总线周期(机器周期)区别
    书单(个人)
  • 原文地址:https://www.cnblogs.com/Youngly/p/4422402.html
Copyright © 2011-2022 走看看