模仿块级作用域
javascript没有块级作用域的概念
function box(count){
for(var i=0;i<count;i++){} //看做块级作用域
var i; //就算重新声明,也不会影响之前声明初始化的数据
alert(i) //块级以外还可以访问到
}
以上例子,说明了Javsscript没有块级作用域,if(){},for(){}等没有作用域,如果有,出了这个范围i就应该被销毁了。就算重新声明同一个变量也不会改变它的值。
Javascript不会提醒你是否多次声明了同一个变量;遇到这种情况,它只会对后续的声明视而不见(付过初始化了,当然还是会执行的)。使用模仿块级作用域可避免这个问题。
//模仿块级作用域(私有作用域)
(function(){
//这里是块级作用域
})();
//使用块级作用域(私有作用域)改写
function box(count){
(function(){ //包含自我执行的匿名函数,就可以实现私有作用域
for(var i=0;i<count;i++){}
})(); //出了这个私有作用域,变量立即被销毁
alert(i) //报错,无法访问
}
使用了块级作用域(私有作用域)后,匿名函数中定义的任何变量,都会在执行结束时被销毁。这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。一般来说,我们都应该尽可能少向全局作用域中添加变量和函数。在大型项目中,多人开发的时候,过多的全局变量和函数很容易导致命名冲突,引起灾难性的后果。如果采用块级作用域(私有作用域),每个开发者既可以使用自己的变量,又不比担心搞乱全局作用域
(function(){
//这里就是全局的私有作用域
var box=[1,2,3,4];
alert(box);
})
在全局作用域中使用块级作用域可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只有函数执行完毕,就可以立即销毁其作用域链了。
私有变量
Javascript没有私有属性的概念;所有的对象属性都是共有的。不过,却又一个私有变量的概念。任何在函数中定义的变量,都可以认为是私有变量,因为不能再函数的外部访问这些变量。
function box(){
var age=100; //私有变量,外部无法访问
}
而通过函数内部创建一个闭包,那么闭包通过自己的作用域链也可以访问这些变量,而利用这一点,可以创建用于访问私有变量的共有方法。
function Box(){
var age=100; //私有变量
function fun(){
return '运行中。。。' //私有函数
}
this.get=function(){ //对外可见的公共接口,特权方法
return age+run();
}
}
var box=new Box();
alert(box.get());
还可以通过构造方法传参来访问私有变量。
function Person(value){
var user=value;
this.getUser=function(){
return user;
}
this.setUser=function(value){
user=value;
}
}
但是对象的方法,在多次调用的时候,会创建多次。可以使用静态私有变量来避免这个问题。
静态私有变量
通过块级作用域(私有作用域)中定义私有变量或函数,同样可以创建对外公共的特权方法。
(function(){
var age=100;
function run(){
return '运行中。。。';
}
Box=function(){}; //构造方法
Box.prototype.go=function(){ //原型方法
return age + run();
};
})();
上面的对象声明,采用的是Box=function(){}而不是function Box(){},因为如果用后面这种,就变成私有函数了,无法在全局访问到,所以使用了前面这种。
(function(){
var user='';
Person=function(value){ //构造函数,在函数里写构造函数不支持,因为私有作用域里的函数,外部无法访问到。
user=value;
/*this.getUser=function(){
return user;
}*/
};
Person.prototype.getUser=function(){
return user;
};
Person.prototype.setUser=function(value){
user=value;
};
})();
使用了prototype导致方法共享了,而user也变成静态属性了。(所谓静态属性,即共享于不同对象中的属性)。
模块模式
之前采用的都是构造函数的方法来创建私有变量和特权方法。那么对象字面量方式就采用模块模式来创建。
var box={ //字面量对象,也是单例对象
age:100, //这是共有属性,也要改成私有
run:function(){ //这是共有函数,将要改成私有
return '运行中。。。'
}
}
私有化变量和函数
var box=function(){
var user='Lee';
function run(){
return '运行中。。。'
}
return {
publicGo:function(){ //对外公共接口的特权方法
return user+run;
}
}
}();
相当于
var box=function(){
var user='Lee';
function run(){
return '运行中。。。'
}
var obj= {
publicGo:function(){ //对外公共接口的特权方法
return user+run;
}
}
return obj;
}();
字面量的对象声明,其实在设计模式中可以看作是一种单例模式,所谓单例模式,就是永远保持对象的一个实例。
增强的模块模式,这种模式适合返回自定义对象,也就是构造函数。
function Desk(){};
var box=function(){
var age=100;
function run(){
return '运行中。。。';
}
var desk=new Desk(); //可以实例化特定的对象
desk.go=function(){
retrun age+run();
}
return desk;
}();
alert(box.go());