• js闭包


    接触过javascript的人应该听过闭包(closure),有一种观点认为是闭包赋予了javascript的强大能力,也赋予了它具备OOP的特征。既然javascript closure如此重要,那么问题来了,什么是closure呢?closure有什么作用?本文将结合我自己对closure的理解,用尽量通俗易懂的方式来进行阐述。

      先看看老外对closure怎么定义的?A closure is an inner function that has access to the outer (enclosing) function's variables—scope chain.从字面上来看,可以翻译为:闭包就是一个内部函数,它具备访问外部函数变量(这些变量位于作用域链中)的能力[注意变量不包含this和arguments]。但这个概念还是过于“专业化”, 不接地气,只从概念上来看,非常抽象。下面用一段JS来对应解释闭包的概念:

    个人理解为:fInner函数定义在fOuter的内部,可以访问fOuter定义的变量,这个fInner函数就是closure。closure的 scope chain有3个:一个是fInner函数定义的变量;一个是外部fOuter的变量;还有一个是全局变量(global variables)。closure的作用可以保留变量的值。换句话说,函数fInner就是一个closure。

      closure可以干2件事情:

      1)closure可以调用(闭包存储的外部变量是引用而不是值,这点非常重要)在当前函数以外的定义的变量(即使外部函数已经返回);

      2)closure可以修改外部定义的变量值。

    下面通过一段JS代码来阐述为什么闭包存储的外部变量是引用而不是值,这点非常重要!

    复制代码
     1     function mixFunction(a)
     2     {
     3         var result=[],i,n;
     4         n=a.length;
     5         for(i=0;i<n;i++){
     6             result[i]=function(){
     7                 //Closure对外部变量是引用
     8                 console.log("for i="+i);
     9                 return a[i];//a[i-1]
    10             }
    11         }
    12         return result;
    13     }
    14     var mixcall=mixFunction([10,20,30]);
    15     var f=mixcall[0];
    16     console.log(f());//?应该输出什么值
    复制代码

    f()会输出 10 么?答案是undefined!!!

    为什么是这样的呢? 因为闭包对i是引用,在for循环时,会不断更新i的值。即在调用f()后,i已经被修改为3 (i===3),而a[3]为undefined!!

    上述的代码始终会输出a[2]的值,也就是30。

     那么问题来了?怎么解决该问题呢?这就要用到JS中的IIFE技术啦!IIFE技术来解决JS缺少块级作用域的解决方案。如下代码所示:

    复制代码
     1     function mixFunctionFix(a)
     2     {
     3         var result=[],i,n;
     4         n=a.length;
     5         for(i=0;i<n;i++){
     6             //IIFE技术来解决JS缺少块级作用域的解决方案
     7             (function(j){
     8                 result[i]=function(){
     9                     //Closure对外部变量是引用
    10                     console.log("for j="+j);
    11                     return a[j];
    12                 }
    13             })(i)
    14         }
    15         return result;
    16     }
    17     var mixcall=mixFunctionFix([10,20,30]);
    18     var f=mixcall[0];
    19     console.log(f());//10
    复制代码

     前面提到JS闭包可以实现OOP的特征,下面给出JS如何定义一个“User类”(实际是一个JS函数)。此函数有私用变量和方法,同时也具有公开的方法。私有变量和方法不能函数外部调用:

    复制代码
     1     function User(){
     2         //private properties
     3         var _name = '';
     4         var _age  = 0;
     5      
     6         //private method
     7         function privateMethod(){
     8             return "private  Method"
     9         };
    10         //public method
    11         this.setName = function(name){
    12             //can call
    13             privateMethod();
    14             _name = name;
    15             return this;
    16         };
    17      
    18         this.setAge = function(age){
    19             _age = age;
    20             return this;
    21         };
    22         this.getAge = function(){
    23             return _age;
    24         };
    25         this.getName = function(){
    26             return _name;
    27         };
    28     }
    29     var p=new User();
    30     console.log(p.setName('jackwang').setAge(28));
    31     console.log(p.getName());//jackwang
    32     console.log(p.getAge());//28
    33     console.log(p._name);//undefined 
    34     console.log(p.privateMethod());//error
    复制代码

    私有变量_name和_age以及私有方法privateMethod()都不能在函数外部调用。User设置name和age只能通过公开方法setName和setAge进行,获取只能通过getName和getAge进行访问。

    有人会问,这个是闭包么?看下图:

  • 相关阅读:
    第四次实验报告
    第三次实验报告
    第五章循环结构课后反思
    第二次实验报告
    第一次实验报告
    第一次作业
    第九章 结构体与共用体
    第八章实验报告
    第七章数组实验
    第六章函数与宏定义实验报告(2)
  • 原文地址:https://www.cnblogs.com/gaoht/p/10430853.html
走看看 - 开发者的网上家园