匿名函数和闭包(下)

http://edu.51cto.com/lesson/id-6390.html

本文主要讲匿名函数中的私有化(私有作用域,私有变量)的问题

一、模仿块级作用域   

1.块级作用域(也叫私有作用域)

function box(){

for(var i=0; i<5; i++){   //for语句为块级作用域(但是在这里不是块级作用域,因为JS没这个东西)

}

alert(i);

}

box(); //输出5  说明for语句里用完之后 没有销毁

 

function box(){

for(var i=0; i<5; i++){  

}

var i;             //就算重新声明,也不会影响之前声明初始化的数据  这里若声明并初始化 var i=1000,则最后输出的是1000

alert(i);

}

box(); //输出5  

以上两个例子说明,javascript没有块级作用域。if(){} for(){}等没有作用域,如果有,出了这个范围 i 就应该呗销毁了。就算重新声明同一个变量也不会改变它的值。

js不会提醒你是否多次声明了同一个变量。遇到这种情况,它只会对后续的声明视而不见(如果初始化了,当然还会执行的)。使用模仿块级作用域可避免这个问题。

2.使用块级作用域(私有作用域)

(达到目的:上面的例子,除了for语句,i 就销毁掉了)

function box(){

(function(){     //包含自我执行的匿名函数,就可以实现私有作用域

for(var i=0; i<5; i++){

alert(i); //输出5次 0 1 2 3 4

}//这里面用了a b c等变量

})();  //出了这个私有作用域,变量立即被销毁  a b c被销毁

//这里可以继续使用a b c等变量,和上面的a b c完全没有联系

alert(i); //这里就不认识了 not defined 

}

box();

 

使用了块级作用域(私用作用域)后,匿名函数中定义的任何变量,都会在执行结束时被销毁。这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。一般来说,我们都应该尽可能少向全局作用域中添加变量和函数。在大项目中,多人开发的时候,过多的全局变量和函数容易导致命名冲突,引起灾难性的后果。如果采用块级作用域(私有作用域),每个开发者既可以使用自己的变量,又不比担心搞乱全局作用域。

我们经常看到js文件(用jQUery写的)这样写

(function($) {  

这里是我们的逻辑。这里可以形成块级作用域,这里定义的任何变量,和方法。而这些变量和方法,在全局作用域中是访问不到的。私有化,保护局部变量。

})(jQuery);

 

这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。这句话理解如下:

程序1

var age=100;

alert(age);//输出100
age=null;

alert(age);//输出null

程序2

(function(){

//这里就是全局的私有作用域

var age=100;

alert(age);

})(); //页面加载,自行执行函数,输出100

alert(age);// age is not defined 即,外部访问不到私有作用域里的age,这里就不用手动添加age=null,age就会自动销毁。

在全局作用域中使用块级作用域可以减少闭包占用的内存问题,因为没有指向匿名函数的引用,只要函数执行完毕,就可以立即销毁其作用域链了。

3.私有变量

javascript没有私有属性的概念,所有的对象属性都是公有的。不过,却有一个私有变量的概念。任何在函数中定义的变量,都可以认为是私有变量,因为不能再函数外部访问这些变量。

 

function box(){

var age=100;  //私有变量,外部无法访问

}

 

function Box(){

this.age = 100; //属性  下面能box.age可以正确输出,说明是公有的

this.run = function(){  //方法   下面能box.run可以正确输出,说明是公有的

return '运行中';

}

}

var box=new Box();

alert(box.age);//输出 100  

alert(box.run());//输出 运行中

而通过函数内部创建一个闭包,那么闭包通过自己的作用域也可以访问这些变量,利用这一点,可以创建用于访问私有变量的公有方法。

function Box(){

var age=100;  //私有变量

function run(){  //私有函数

 return'运行中';

}

this.publicGo= function(){   //对外可见的公共接口,特权方法

return age+run();

};

}

var box = new Box();

alert(box.publicGo());

 

//通过构造函数传参 来访问私有变量

function Box(value){

var user=value;  //私有变量

this.getUser=function(){

  return user;

};

this.setUser= function(){

  user=value;

}

}

var box = new Box('lee');

alert(box.getUser());  //输出lee

box.setUser('ooo');  //重新赋值

alert(box.getUser());  //输出ooo

但是对象的方法,在多次调用的时候,会多次创建。可以使用静态私有变量来避免这个问题。

静态私有变量 

通过块级作用域中定义私有变量或函数,同样可以查ungjianduiwai公共的特权方法。

//

(function(){

var user ='' // 私有变量

//function Box(){}  //构造函数,但是在函数里面写构造函数,不支持,因为私有作用域里的函数,外部无法访问

Box=function(value){

user=value;

}; //全局,构造函数   里面没有var 就说明是全局的

Box.prototype.getUser = function(){ //使用prototype导致方法共享了,而user变成了静态属性。

return user;

};

Box.prototype.setUser= function(value){

  use=value;

}

})();

var box = new Box('lee');//第一次实例化

alert(box.getUser());   //输出lee

var box2 = new Box('kkk');//第二次实例化

alert(box.getUser());  //输出kkk  实现了共享

box2. setUser('OOO');

alert(box.getUser()); //输出OOO 实现了共享

4.模块模式

之前采用的都是构造函数的方式来创建私有变量和特权方法,那么对象字面量方式就采用模块模式来创建。这里采用对象字面两方式来创建私有变量和特权方法。

什么叫单例,就是永远只实例化一次,其实就是字面量声明方式

var box={  //第一次实例化,无法第二次实例化,那么就是单例

user :'lee',

run : function(){

 return '行中';

};

//字面量方式 私有化变量和函数

var box = function(){

var age=100; //私有变量

function run(){  //私有函数

 return'运行中';

}

return {  //直接返回对象

  go:function(){    //对外公共借口的特权方法

    return age+run();

    }

};

}();//自我执行的函数

alert(box.go());  //输出 100运行中

 

上面直接返回对象的例子也可以这么写

var box = function(){

var age=100; //私有变量

function run(){  //私有函数

 return'运行中';

}

var obj= {  //直接返回对象

  go:function(){    //对外公共借口的特权方法

    return age+run();

}

};

return obj;

}();//自我执行的函数

alert(box.go());  //输出 100 运行中

 

字面量的对象声明,其实在设计模式中可以看作是一种单例模式,所谓单例模式,就是永远保持对象的一个实例。

增强的模块模式,这种模式适合返回自定义对象,也就是构造函数

//之前的两个例子都是返回的{}  也就是object,如果想返回自定义的呢?例如Desk

function Desk(){};

var box = function(){

var age = 100;

function = run(){

  return'运行中';

}

var desk = new Desk();

desk.go = function(){

  return age+run();

}

return desk;

}();

alert(box.go());

posted @ 2014-05-08 17:39  mabel_on_line  阅读(485)  评论(0编辑  收藏  举报