JS的封装

         封装是面向对象设计的基石,封装是什么,封装有何用,这些常识性的问题在这里不做介绍。尽管JS是一种面向对象的语言,但是它不具备用以将成员声明为公用或私用的任何内置机制。与上篇讲述的接口一样,我们将自己想办法实现这种特性。这里主要利用了JS的闭包。什么是闭包,这里也不作讨论,这不是一个讨论JS语法的总结。


       2.JS创建自定义对象的基本方法

      通过JS创建自定义对象主要有两种方法,一种是通过字面量对象,这种方法等价于实例化一个Object对象,给实例化的对象添加各种属性和方法; 第二种是通过构造函数的形式实例化对象。以下代码展示了这两种创建对象的方法。

[javascript] view plaincopy

    /*通过字面量创建对象,等价于var obj=new Object(); obj.name='xxx', obj.age=23, obj.getName=function(){return this.name;}*/
    var obj = {
        name: 'xxx',
        age: '23',
        getName:function(){
              return this.name; },
       ..............
    };
      
    /*通过构造函数实例化一个对象*/
    function Person(name, age){
         this.name = name;
         this.age = age;
         this.getName=function(){
                  return this.name;
         };
    }
      
    var obj_person = new Person('xxx', 23);


通过字面量创建对象常用于保存一些数据,或者实现一个简单的单例对象,我们可以看到,无法从这种创建对象的方法隐藏任何信息。

通过构造函数实例化对象,很显然,非常符合面向对象的特点,且我们可以通过该方法实现封装的特性。


3. 利用闭包和构造函数实现私有成员和特权方法

       假设你想定义一个Person类,这个Person包含有name, age这两个属性,同时对age字段还提供了对应的get和set操作,而name字段我们不希望有人去更改他,只提供get方法,同时为了规范, 每个私有成员的命名都应该以'_'开头,很自然的,你可以这样定义构造函数:

[javascript] view plaincopy

    function Person(name, age){
         this._name = name;
         this._age = age;
         this.getAge = function(){
              return this.age;
         };
         this.setAge = function(value){
             if(value < 0){
                 throw new Error("Age of a Person cannot be a minus"); //人的年龄是不能为负数的,在这里做个简单的值检验
             }
             this.age = value;
         };
         this.getName = function(){
             return this.name
         };


事实上,这样只能从命名规范上来约束使用你的代码的程序员,如果用你的代码的程序员想更改这些目前所谓的私有成员,是非常容易的:

只需 var obj = new Person(); obj._age = -10; 为了解决这类问题,我们可以按如下代码所示使用闭包实现私有成员:

[javascript] view plaincopy

    function Person(name, age){
        if (age < 0) {
            throw new Error("Age of a Person cannot be a minus");
        }
          
        //私有成员,仅内部可见,只能通过特权方法访问
        var _name = name,
            _age = age;
          
        //get和set特权方法
        this.getName = function(){
            return _name;
        };
          
        this.getAge = function(){
            return _age;
        };
        this.setAge = function(value){
            if (value < 0) {
                throw new Error("Age of a Person cannot be a minus");
            }
            _age = value;
        };
    }


      4. 用闭包实现私有成员的弊端
      从上面的闭包代码可以看到,内部访问私用成员的方法在每一个对象中都必须存在一份副本,即使他们实现的功能和代码是一样的,在普通的模式中,通过原型链可以只保存一份通用的方法,即可以这样定义类的get和set: Person.prototype.getName = function(){ return this.name; }; 因此通过闭包的形式实现的特权方法会造成更多的内存消耗,在开发团队中,一般通过命名规范的模式应该就可以保证私有成员的完整性。
   
    5. 静态方法和属性
    现在,假设我们的客户提出了一个新的需求,需要一个方法能统计人数,自然的这个人数就是Person实例化后的对象个数,同样我们很自然的想到可以通过一个静态变量来统计,再一次的,我们也不想别人可以任意的修改这个数值,因此我们同样通过闭包来实现私有的静态属性,并提供一个公共的静态方法让用户可以获得人数。同时,我们进一步细化原来的代码,把验证年龄合法性的代码封装成一个静态私有函数。 以下代码展示了上面所述的实现:

[javascript] view plaincopy

    //这里使用了一个自运行函数实现闭包
    var Person = (function(){
        var personNumbers = 0; //静态私有成员,记录实例化个数
        function _checkAge(value){ //静态私有方法,检验年龄的合法性
            if (value < 0) {
                throw new Error("Age of a Person cannot be a minus");
            }
        }
          
        var cstor = function(name, age){ //将返回的构造函数
            _checkAge(age);
            //私有成员,仅内部可见,只能通过特权方法访问
            var _name = name,
                _age = age;
                  
            ++personNumbers;//增加实例化个数
            //get和set特权方法
            this.getName = function(){
                return _name;
            };
          
            this.getAge = function(){
                 return _age;
            };
            this.setAge = function(value){
                _checkAge(age);
                _age = value;
            };
        };
          
        cstor.getPersonNumbers = function(){ //静态公有方法,返回实例化个数
            return personNumbers;
        };
          
        return cstor;
    })();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值