在Javascript--闭包一节中我们讲解了闭包的作用域和作用域链的特性。了解到在外部一般是不可能访问到内部作用域中的变量的,然而通过闭包我们可以定义特权方法访问私有变量。下面先介绍块级作用域再介绍几种特权方法。
一、模仿块级作用域
Javascript是没有块级作用域的概念的。所以我们在语句块中定义的变量,其作用域是包含函数而非语句块。
function outPut(count){ for(var j=0;j<count;j++){ alert(j); } alert(j); //计数 }
在Java、C++语句中,变量j在循环语句结束后就销毁了。但再Javascript中,变量j则是函数outPut的变量。因此我们通过函数表达式的变式来模仿块级作用域。
function outPut(count){ (function (){ for(var j=0;j<count;j++){ alert(j); } })(); alert(j); //error }
这个时候变量j只在私有作用域中有效,运行结束就销毁。这种技术经常在全局作用域中被用在函数外部,从而限制向全局环境中添加过多变量、函数。
二、构造函数访问法
现在我们介绍第一种访问私有变量的方法--构造函数法。私有变量指在函数内部中定义的变量、参数及其它函数。
function Person(name){ var name=name; this.sayName=function(){ alert(name); } }; var person1=new Person("Bob"); var person2=new Person("Mike"); person1.sayName(); //Bob person2.sayName(); //Mike
sayName()方法就是Person所有实例的一个特权方法。但有个问题:
alert(person1.sayName==person2.sayName); //false
每个实例的同名特权方法都要重新创建。
三、借用原型访问
function Person(name){ var name=name; Person.prototype.sayName=function(){ alert(name); } };
var person1=new Person("Bob"); person1.sayName(); //Bob var person2=new Person("Mike"); person1.sayName(); //Mike person2.sayName(); //Mike alert(person1.sayName==person2.sayName); //true
这种方法每个实例的特权方法都是动态共享的。但每个实例都没有自己的私有变量。
四、组合访问
function Person(name){ var name=name; Person.prototype.sayName=function(){ alert(name); }; this.sayPrivateName=function(){ alert(name); } };
将两种方式融合,看看其访问私有变量的效果:
var person1=new Person("Bob"); person1.sayName(); //Bob person1.sayPrivateName(); //Bob var person2=new Person("Mike"); person1.sayName(); //Mike person1.sayPrivateName(); //Bob person2.sayName(); //Mike alert(person1.sayName==person2.sayName); //true alert(person1.sayPrivateName==person2.sayPrivateName); //false
私有变量若痛过原型方法访问,私有变量就是动态共享的;若通过实例方法访问,私有变量在每个实例中都有其特异性。而实例属性不同,实例属性将覆盖同名原型属性,且永远是特异性的。
五、模块模式
前面的方法都是为自定义类型创建特权方法,而模块模式是为单例创建特权方法。
var person=function(){ var name="Bob"; //私有变量 function privateFunction(){ //私有函数 alert(true); }; return { publicName:name, //特权属性 publicMethod:function(){ //特权方法 return privateFunction(); } } }();
alert(person.publicName); //Bob person.publicMethod(); //true
简言之,如果必须创建一个对象并对其进行初始化,且还要公开一些能够访问这些私有变量的方法,那么就可以使用模块模式。
时间: 2024-10-29 19:07:40