JavaScript中私有变量的使用

JavaScript中私有变量的使用


JavaScript中没有私有成员的概念;对象属性是公有的。但JavaSctipt中有个私有变量的概念: 任何在函数内部定义的变量都可以认为是私有变量,它只在这个函数内部有效,不能通过外部函数来访问。私有变量大概有:函数参数、局部变量和函数中嵌套的函数

function add (num1, sum2) {
    var sum = num1 + num2;
    return sum;
}

add(1, 2);


在这个函数中,有三个私有变量:num1、num2、sum。在函数内部可以访问这三个变量,但外部是没有办法访问到的。此时,如果在这个函数内部创建一个闭包,那么闭包可以通过自己的作用域链来访问这三个私有变量。利用闭包可以创建访问私有变量的公有方法。

把有权访问私有变量和私有函数的公有方法称 特权方法。创建特权方法有两种方式:

第一种,在构造函数中定义特权方法,基本模式为:
function MyObject () {
    //创建私有变量和私有函数
    var a = 5;

    function getFunc () {
        return false;
    }

    //创建特权方法,访问私有变量和私有函数。
    this.func = function () {
        a ++;
        return "a:" + a + " " + getFunc();
    };
}

var myObject = new MyObject();
console.log(myObject.func()); //调用func()函数来访问构造函数中的私有成员

以上代码,在构造函数中定义私有变量和私有函数,以创建了一个可以访问这些私有成员的特权方法。这个特权方法之所以可以访问这些私有成员,是因为这个特权方法是作为闭包函数有权访问包含函数的所有变量和函数。在创建MyObject的实例后,除了使用func()这个方法外,没有其它方法可以访问这些私有成员。

function Peron (name) {
    this.getName = function () {
        return name;
    };

    this.setName = function (value) {
        name = value;
    };
}

//创建实例

var person = new Person("Tom");
console.log(person.getName()); // Tom

person.setName("Bob"); //修改name的值
console.log(person.getName()); //Bob

以上代码为构造函数Person定义两个特权方法:getName()和setName()。它们可以在构造函数外部使用,而且都有权访问私有变量name。在构造函数外部也只能通过这两个方法来访问私服变量name,因为这两个方法是作为构造函数的闭包存在的。getName()用于得到name的值,而setName()用于修改name的值。这样就不会直接修改数据了。私有变量name在每个实例中都不相同,因为每次调用构造函数都会重新创建这两个方法。

构造函数中定义特权方法有个缺点:那就是 必须使用构造模式来实现这个目的。而 构造模式有个缺点:每个实例都会重新创建同样的方法。使用静态私有变量实现特权方法可以避免这个问题。



静态私有变量


第二种创建特权方法的方式,在私有作用域中定义私有变量或函数来创建特权方法。

(function () {
    //私有变量和函数
    var a = 5;

    function getFunc () {
        return false;
    }

    //使用函数表达式来定义构造函数
    MyObject = function () {
    };

    //特权方法
    MyObject.prototype.func = function () {
        a ++;
        return "a:" + a + " " + getFunc();
    };
})();

var myObject = new MyObject();
console.log(myObject.func()); //a:6 false

以上代码要注意的是:构造函数没有使用函数声明方法(funciton关键字)来定义,因为在匿名函数中使用function关键字来定义构造函数的话,那么这个构造函数就成了局部函数时,只能在该匿名函数中访问,不符合我们要求。使用 函数表达式方式来定义变个构造函数,并且没有使用关键字var,就是为使这个构造函数成全局函数,能够在匿名函数之外被访问到。特权方法是在构造函数的原型上定义的,这样这个特权方法每个实例可以共享。 这个模式与构造函数模式有个区别就是:私有变量和私有函数都是实例共享的,因为原型上的特权方法保存着对私有变量与函数的引用。特权方法是在原型上定义的,因为所有实例都共享这个特权方法。这个特权作为闭包,总是保存着对包含作用域的引用(包含函数中的变量和函数的引用)。

(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("Tom");
console.log(person1.getName()); //Tom
person1.setName("Bob");
console.log(person1.getName());  //Bob

var person2 = new Person("Jon");
console.log(person1.getName()); //Jon
console.log(person2.getName());  //Jon

Person与setName、getName一样都有权访问私有变量name。在这种模式下,name变成了静态的、所有实例共享的发展,因为通闭包可以访问到。setName和getName方法在构造函数的原型中定义的,因此所有实例都共享这两个方法,在一个实例中使用setName()会影响所有实例。而使用setName()函数和定义一个新实例,都相当于重新定义了私有变量name,所有实例都会的返回相同的name值。

使用这种模式,会因为原型而增加代码的复用,每个实例都没有自己的私有变量(由原型链创建对象也这个特点)。



模块模式


以上同种模式是为 自定义类创建私有变量和特权方法的 。模块模式是为 单例创建私有变量和特权方法的。 所谓单例就是只有一个实例的对象,也就是通过对象字面量创建的对象。

var obj = {
    name : "Tom",
    getName : functin () {
        return name;
    }
};


模块模式通过为单例创建私有变量和特权方法得到增强。

var singleton = function () {
    //私有变量和函数
    var a = 5;
    
    function getFunc () {
        return false;
    }

    //特权方法/公有属性和方法
    return {
        publicprototype : true,
        func : function () {
            a ++;
            return "a:" + a + " " + getFunc();
        }
    };
}();


这个模式使用了一个返回对象的匿名函数。首先定义了私有变量和函数,然后将一个对象字面量作为函数的值返回。这个对象字面量只包含公开的属性和方法,由于这个对象是在匿名函数内部定义,因此可以访问私有变量和函数。这种对单例进行某些初始化,同时又要维护其私有变量是有用的:

var application = function () {
    var arr = new Array();
    
    //初始化数组
    arr.push(new BaseCom());

    return {
        getLength : function () {
            return arr.length;
        },
        regArr : function (newArr) {
            if (typeof newArr == "Object") {
                arr.push(newArr);
            }
        }
    };
}();


返回的对象字面中,前者函数用于检测组件数目,后者用于添加新的组件。


如果必须创建一个对象并以某些数据进行初始化,同时要公开一些私有变量,就可以使用这种模式。



增强的模块模式


模块模式还可以对返回的对象进行增强操作,即 单例必须是某类型的实例,并且 还为其添加某些属性和方法对单例进行加强。

var singleton = function () {
    //私有变量和函数
    var a = 5;

    function getFunc () {
        return false;
    }

    //创建对象,单例是某类型的实例
    var obj = new CustType();

    //为这个对象添加属性和方法
    obj.publicPrototype = true;
    obj.func = function () {
        a ++;
        return "a:" + a + " " + getFunc();
    };

    //返回这个对象
    return obj;
}();

下例是application必须是BaseComr的实例:

var application = function () {
    var arr = new Array();
    
    //初始化数组
    arr.push(new BaseCom());

    //创建BaseCom的实例
    var app = new BaseCom();

    //为这个实例添加属性和方法
    app.getLength = function () {
        return arr.length;
    };

    app.regArr = function (newArr) {
        if (typeof newArr = "Object") {
            arr.push(newArr);
        }
    };

    return app;

}();


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值