Javascript高级程序设计_6_闭包

Posted on 2018-02-05 00:46  Jonathan_C  阅读(115)  评论(0)    收藏  举报
  • 首先要明白一点,闭包比较消耗资源。看下面这个函数:
 1         function createFunctions(){
 2             var arr=new Array();
 3             for(var i=0;i<10;i++){
 4                 arr[i]=function(){
 5                     return i;
 6                 };
 7             }
 8             return arr;
 9         }
10         var a=createFunctions();
11         console.log(a);

  这个函数的意图目的是为了返回一个数组,数组有十个整数,分别从0-10。但是运行后结果为: [ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ],生成的全部都是f对象实例。如果想要生成意图中的结果,只需要:

 1         function createFunctions(){
 2             var arr=new Array();
 3             for(var i=0;i<10;i++){
 4                 arr[i]=function(){
 5                     return i;
 6                 }(i);
 7             }
 8             return arr;
 9         }
10         var a=createFunctions();
11         console.log(a);
  • this 对象的作用域和闭包
 1         //this object
 2         var name="window";
 3         var object={
 4             name:"object",
 5             getName: function(){
 6                 return function(){//return的为一个匿名的函数,而其作用域为全局
 7                     return this.name;
 8                 }
 9             }
10         }
11         console.log(object.getName()());//the window

   这里的返回式window,。表示this的调用者为全域的window。为什么在对象内声明了,却不显示object。因为返回的式匿名函数,作用域在全局,如果不显式声明,那么默认为全局作用域。改善的方法为:

 1         var name="window";
 2         var object={
 3             name:"object",
 4             getName: function(){
 5                 var obj_this=this;
 6                 return function(){
 7                     return obj_this.name;
 8                 }
 9             }
10         }
11         console.log(object.getName()());//object

  定义闭包前,this对象赋给obj_this,那么定义闭包后,即可调用object对象的name。

  • 内存泄漏问题
1         function handler(){
2             var elements=getDocumentsById("id");
3             elements.onclick=function(){
4                 alert(elements.id)
5             }
6         }

    这个函数的活动对象为elements,同时函数内部具有一个对这个elements的引用(因为匿名函数要求返回它的id),那么这个引用会占用内存,且无法消除。

1         function handler(){
2             var elements=getDocumentsById("id");
3             var id=elements.id
4             elements.onclick=function(){
5                 alert(id)
6             }
7             elements=null;
8         }

    改变的方法也不难,只需要将elements的id赋给一个id副本,然后将elements这个引用置空即可。

  • 块级作用域

    如果想要将函数声明变成函数表达式,需要在函数外部加一个括号,再即刻调用才行,否则会报错。

1         (function (){
2             alert('hi');
3         })();

    而内部alert部分为块级作用域

  • 私有变量

    任何在函数中定义的变量,都可以称作私有变量

 1         //private variable
 2         function myObject(){
 3             var privateVal=10;
 4             function privateFunc(){
 5                 return false;
 6             }
 7             this.publicFunc=function(){//previleged method
 8                 return privateFunc();
 9             }
10         }

    myObject为函数对象,里面有一个私有的privateVal和一个私有函数privateFunc,同时通过特权方法:即调用闭包函数publicFunc来访问、修改和返回私有变量。  

    要记住特权函数的声明方式:

    this.xxx=function(){......)

  • 静态私有变量:
  1. 为什么需要静态私有变量?因为调用这个构造函数的时候,每个实例都会创建同样一组新的方法,例如var person=new function("Mike")的同时,会创建一组新的getName等方法,这样比较占内存,所以通过创建静态私有变量,让每个实例共享这些方法,会比较方便
  2. 如何创建静态私有变量?
 1         //private static variable
 2         (function(){
 3             var privateVal=10;
 4             function privateFunc(){
 5                 return false;
 6             }
 7             myObject=function(){};//不用var,使得myObjct这个构造函数可以在全局访问。
 8             myObject.prototype.publicFunc=function(){
 9                 privateVal++;
10                 return privateFunc();
11             }
12         })();

    首先,创造一个私有作用域

    接着,前半部分没什么变化,主要是后面两个步骤不同。分别为创建一个构造函数myObject,然后在其原型上定义一个共有变量,这样所有实例就会共享这个publicFunc方法。

    这样,privateVal和privateFunc便由实例所共享,所有的实例通过原型上的publicFunc方法来访问私有变量。

  • 模块模式
  1. 该模式使用单例方法,借助匿名函数实现。
 1         //block mode
 2         var singleton=function(){
 3             var privateVal=10;
 4             function privateFunc(){
 5                 return false;
 6             }
 7             return{
 8                 publicProperty:true;//不用var声明,全局作用域
 9                 publicFunc:function(){
10                     privateVal++;
11                     return privateFunc();
12                 }
13             }
14         }

    2.  如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有 数据的方法,那么就可以使用模块模式