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

     闭包:闭包的功能是当父作用域执行完,仍能访问自身声明的作用域和父作用的函数,对这句话我有下面的两个理解

      1 闭包是一种函数,在它的定义中存在对父作用域变量和函数的引用,才能导致父作用域执行完仍能访问父作用域

      2 闭包是一种嵌套函数函数声明,将它返回给外部的变量(本身也是一种引用),这样一直存在对父作用域的引用,就能使父作用域不被垃圾回收机制回收,达到相应的功能   

          2016.6.1  3 闭包是函数代码和其[[scope]]相结合的结果   

     (在ECMAScript里 理论上所有函数都是闭包 函数在创建的时候就保存了父级的作用 保存在[[scope]]属性中)

     function test() {
        var name = 'haha';
        function sayName() {
          console.log(name);
        }
        sayName();
      }
      test();//haha

    上面的例子中就是一种嵌套函数的声明,在test()内部定义了一个局部的变量(属性)name,并且在它内部定义了一个函数sayName()并且引用了它的属性name

    在javascript中调用函数的时候会隐式的生成call对象,也就是活动对象,活动对象中包含着它的作用域和所访问的属性,在结合作用链域达到对付作用域属性的访问

    上面的例子中,调用test(),在test()中调用sayName(),此时生成sayName的活动对象,沿着作用链域找到父作用域的name属性,sayName执行完毕后,它的活动对象被销毁,到达test的活动对象,最后销毁test的活动对象

      我们可以换一种方案  

     

     function test() {
       var name = 'haha';
        return function sayName() {
          console.log(name);
        }
      }
      var func = test();
      func();//haha

      test()执行完毕,它的name属性应该不能被外部访问的(理应被垃圾回收),这是为什么呢?

      在test()内部定义了一个这样的函数(可以理解函数是test()的一个属性),它中存在对父作用域属性的访问,当我们把这个函数(属性)放回给外部的变量,在外部就存在对test()的属性的访问,导致test()不会被垃圾回收,所以我们仍能保证对test()的属性的访问,这就是闭包的基本原理,并且闭包引用的是当时的test()活动对象

    闭包是一种特殊的函数,它在调用的时候会保持当时的变量名的查找的执行环境,也可以将它理解为具有状态的函数(javascript编程全解)

    一个需要注意的问题 

    function test() {
      var num = 1;
      function sayNum1() {
      console.log(num);
      }
      num++;
      function sayNum2() {
      console.log(num);
      }
      return [sayNum1,sayNum2];
    }
    
    var func = test();
    func[0]();//2
    func[1]();//2

    在上面的例子中,返回了两个函数,他们都引用了test的活动对象形成闭包,之所以要用这个例子是因为声明两个函数的时候num的值虽然不一致但是他们最终都是引用test的活动对象,所以会返回相同的结果,由此我想起我去面试的一次尴尬经历,在<li><li>上绑定onclick事件,单击相应的列表项是现实显示相应的序号,我当时的写的就不贴了,就是全部返回一个值,下面把正确的贴下来(还好回来又考虑了那个问题)

    function test() {
      var lis = document.getElementById('container').getElementsByTagName('li');
        for(var i = 0;i < lis.length;i++) {
          lis[i].onclick = function(j){
            return function() {
              console.log(j);
              }
                }(i);
           }
    }

    上面的例子我们通过内部创建的函数 为它传递一个参数 ,也就是它保存了当时的值  但是这时你访问外面的i值它仍然是一个值

    下面在介绍闭包的几种用法,也算回答了另一次面试的问题

    1)可以通过闭包实现对信息的隐藏

      结构是这样的 (function(){函数体})();

      我们当即的调用匿名函数,但是在利用闭包使得变量在调用后依然存在的特点 

      

    var obj = (function(){
                    var position = {x:2,y:3};
    
                    function sum_internal(a,b) {
                        console.log(Number(a) + Number(b));
                    }//position和sum_internal(a,b)相当于私有变量和函数(属性)
    
                    return {
                        sum:function(a,b) {return sum_internal(a,b);},
                        x: position.x,
                        y: position.y
    
                    };
                })();
    
                obj.sum(1,5);//6
                console.log(obj.x);//2

    上面的例子通过返回字面量的形式实现了对信息的隐藏

    利用上面的方法可以将闭包与类进行结合,实现访问控制

    function Person(name) {
    				this.name = name;
    
    				this.sayName = function() {
    					console.log(this.name);
    				}
    			}
    
    			var person1 = new Person('haha');
    			person1.sayName();
    

     上面是一个简单的类的定义,在我的另一篇博客中也对这个例子进行了说明  原型继承 javascript 

     我们可以将上面的定义写成下面的形式,结合闭包

    function Person(name) {
                    return {sayName: function(){console.log(name);}};
                }
    
                var obj = Person('haha');
                obj.sayName();

     2016 7 6   之前理解错误的点

       var prison = {
           name:"haha",
           who:function() {
             $.ajax({
              success:function(){
                console.log(this.names);
              }
             });
           } 
       }
       person.who();

    在发送ajax请求的时候,这里的this不在指向person对象 而是ajax的请求对象   

    我们可以通过闭包的的方式 保存外部这个对象  

        var person = {
          name:"hah",
          who:function() {
            var that = this;
            $.ajax(function(){
              success:function() {
                console.log(that.name);
              }
            });
          }
        }  
  • 相关阅读:
    http状态码
    Django基础篇(二)
    Django基础篇
    mysql进阶
    mysql数据库的基本操作
    JavaScript
    分布式原理之RPC框架
    Java实现本地缓存
    模版方法模式:封装算法 && 迭代器与组合模式:管理良好的集合
    分布式高并发系统设计与分析
  • 原文地址:https://www.cnblogs.com/tiantianwaigong/p/4395517.html
Copyright © 2011-2022 走看看