javascript--特权方法

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

简言之,如果必须创建一个对象并对其进行初始化,且还要公开一些能够访问这些私有变量的方法,那么就可以使用模块模式。