私有变量
任何在函数中定义的变量,都可认为是私有变量,因为不能在函数外部访问这些变量。私有变量包括函数的参数、局部变量、在函数内部定义的其它函数。
如下代码:
function add(bum1,num2){
var sum=num1+num2;
return sum;
}
在这个函数中,有3个私有变量:num1、num2、sum。在函数内部可以访问这些私有变量,但是在函数外部不能访问它们。
如果再这个函数内部创建一个闭包,那么这个闭包也可以通过作用域链访问到这些变量。利用这一点,就可以创建访问私有变量的共有方法。我们把有权访问私有变量和私有函数的公共方法称为特权方法。
在对象中创建特权方法的方式:
方式一:在构造函数中定义特权方法:
如下面实例:
function myObject(){
var privateVariable=10;
function privateFunction(){
return false;
}
// 特权方法
this.publicMethod=function () {
privateVariable++;
return privateFunction();
}
}
var age=new myObject();
alert(age.publicMethod());//false
这种模式在构造函数中定义了所有私有变量和函数。能够在构造函数中定义特权方法是因为特权方法作为闭包,能够访问在构造函数中定义的所有变量和函数。
利用私有和特权成员能够隐藏那些不应该被直接修改的数据。
function Person(name){
this.getName=function(){
return name;
};
this.setName=function(value){
name=value;
};
}
var person=new Person('Lee');
alert(person.getName());//'Lee'
person.setName('lwf');
alert(person.getName());//'lwf'
私有变量name在Person的每个实例中都不相同,因为每次调用构造函数都会重新创建这两个方法。不过,在函数中定义特权方法也有一个缺点,就是你必须使用构造函数来达到这个目的。
构造函数模式的缺点就是针对每个实例都会创建同样一组新方法,而使用静态私有变量来实现特权方法就可以避免这个问题。
方式二:使用静态私有变量来实现特权方法:
(function(){
var privateVariable=10;
function privateFunction(){
return false;
}
//构造函数
MyObject=function(){
};
//公有/特权方法
MyObject.prototype.publicMethod=function(){
privateVariable++;
return privateFunction();
}
})();
这种模式创建了一个私有作用域,并在其中封装了一个构造函数及其相应方法。共有方法是在原型的基础上定义的,这一点体现了典型的原型模式。需要注意的是,这种模式在定义构造函数时,并没使用函数声明,而是使用了函数表达式。函数声明只能创建局部函数,但那并不是我们想要的。出于同样的原因,我们也没有在声明MyObject时使用var关键字。记住:初始化未经声明的变量,总会创建一个全局变量。因此,MyObject就是一个全局变量,能够在私有作用域外被访问到。但也要知道,在严格模式下,给未经声明的变量赋值会导致错误。
这种模式与在构造函数中定义特权方法的主要区别就在于变量和函数是由实例共享的,由于特权方法就是在原型的基础上定义的,因此所有实例都是用同一个函数。而这个特权方法,作为一个闭包,总是保存着对包含作用域的引用。
如:
(function(){
var name='';
Person=function(value){
name=value;
};
Person.prototype.getName=function(){
return name;
};
Person.prototype.setName=function(value){
name=value;
}
})();
var person1=new Person('Lee');
console.log(person1.getName());
person1.setName('lwf');
console.log(person1.getName());
var person2=new Person('aaa');
console.log(person2.getName());
console.log(person1.getName());
person2.setName('bbb');
console.log(person2.getName());
console.log(person1.getName());
结果为:
在这个例子中Person构造函数与getName()和setName()方法一样,都有权访问私有变量name,在这种模式下,变量name就是一个静态的、由所有实例共享的属性。也就是说,在一个实例中,调用setName()会影响所有实例,而调用setName()或者新建一个Person实例就会赋予name 一个新值。结果就是所有实例返回相同的值。
有这种方式创建静态私有变量会因为使用原型而增进代码复用,但每个实例都没有自己的私有变量。到底是使用实例变量还是静态私有变量还是要看你的具体需求而定。