zoukankan      html  css  js  c++  java
  • 基本封装方法

     

    请看下面的例子:

    var Person = function(name,age){
      this.name = name;
      this.age = age || "未填写";
      this.hobbys = [];
    }
    
    Person.prototype = {
      sayName:function(){
        console.log(this.name);
      },
      sayAge:function(){
        console.log(this.age);
      },
      addHobby:function(hobbys){
        this.hobbys = this.hobbys.concat(hobbys);
      }
    }
    
    var person1 = new Person("Jane","20");
    var person2 = new Person("TabWeng","21");
    
    person1.addHobby(['sing','drawing']);
    person2.addHobby(['football','study','running']);
    
    person1.sayName();
    console.log(person1.hobbys.toString());
    
    person2.sayName();
    console.log(person2.hobbys.toString());

    运行结果:

    Jane  
    sing,drawing
    TabWeng  
    football,study,running

    这在JavaScript创建对象中讲过,把可以共用的属性和方法写在原型上,需要每个实例各自都有的副本的属性和方法放在构造函数中。

    现在有个问题,名称的输入不能有数字,要怎么解决呢?解决的方法可以写一个检查名称的函数,这个函数写在原型上。

    var Person = function(name,age){
      //校验名称
      if(this.checkName(name)){
        throw new Error("名字 "+name+" 不能存在数字");
      }
      this.name = name;
      this.age = age || "未填写";
      this.hobbys = [];
    }
    
    Person.prototype = {
      //校验函数
      checkName:function(name){
        re = /d/;
        return re.test(name);
      },
      sayName:function(){
        console.log(this.name);
      },
      sayAge:function(){
        console.log(this.age);
      },
      addHobby:function(hobbys){
        this.hobbys = this.hobbys.concat(hobbys);
      }
    }
    
    var person1 = new Person("Helen666","20");
    var person2 = new Person("TabWeng","21");
    
    person1.addHobby(['sing','drawing']);
    person2.addHobby(['football','study','running']);
    
    person1.sayName();
    console.log(person1.hobbys.toString());
    
    person2.sayName();
    console.log(person2.hobbys.toString());

    这段代码中,我们写了一个checkName()函数,来校验名称,暂且只是校验不能有数字吧,然后再构造函数里的第一行代码中进行校验,若校验不通过,则抛出异常。
    这里我传入一个名称Helen666,结果抛出如下异常:

    Error: 名字 Helen666 不能存在数字

    这样就做到了一个基本的封装,实现内部校验。

    但是又有个问题,我们还可以这样来定义名称:

    var person1 = new Person("Helen","20");
    person1.name = "Helen666";
    person1.sayName(); //Helen666

    这样名称还是可以修改为不合法的名称,于是我们想到用get方法 和set方法来做控制,只能通过set方法来赋值,同时通过set方法进行校验,而通过get方法来获得值。现在的代码修改如下:

    // Interface
    var People = new Interface("People",["setName","getName","setAge","getAge","addHobby","getHobby","sayName","sayAge"]);
    
    var Person = function(name,age){ //implement People
      this.setName(name);
      this.setAge(age);
      this._hobbys = [];
    }
    
    Person.prototype = {
      //校验函数
      checkName:function(name){
        re = /d/;
        return re.test(name);
      },
      sayName:function(){
        console.log(this._name);
      },
      sayAge:function(){
        console.log(this._age);
      },
      addHobby:function(hobbys){
        this._hobbys = this._hobbys.concat(hobbys);
      },
      getHobby:function(){
        return this._hobbys;
      },
      setName:function(name){
        if(this.checkName(name)){
          throw new Error("名字 "+name+" 不能含有数字");
        }
        this._name = name;
      },
      getName:function(){
        return this._name;
      },
      setAge:function(age){
        this._age = age || "未设置"; 
      },
      getAge:function(){
        return this._age;
      }
    
    }
    
    var person1 = new Person("Helen","20");
    person1.addHobby(['sing','drawing']);
    
    function record(person){
      Interface.ensureImplements(person,People);
      person.sayName();
      console.log(person.getHobby().toString());
    }
    
    record(person1);

    运行结果:

    Helen
    sing,drawing

    首先,这段代码我们使用了接口,定义了People接口,而person来实现这个接口,注意注释的内容。(关于接口,请看这篇 JavaScript使用接口
    其次,我们使用了get方法 和 set方法来取值和赋值,我们可以约定程序员只能通过set来赋值,而在set方法里面我们对所赋予的值进行了校验,以确保准确。但是这仅仅是一种约定,程序员依然可以通过 person1.name = "123" 来赋值,修改内部属性。
    为了规范和起到提醒作用,我们把内部属性的命名进行规范,在这些属性前面加上“_”,比如 **_name** 、**_age** ,这样如果程序员要直接修改属性,那么他就必须这样写person1._name = "123",这明显是一种故意的做法,一般程序员不会这么做,起到规范和提醒的作用。

    尽管如此,这种仅仅是用规定进行约束,还是无法阻止通过person1._name进行修改,下面的方法可以做到把内部属性真正做到私有化。

    通过闭包进行封装

    如果对闭包不太理解,请阅读JavaScript函数表达式以及JavaScript变量和作用域,我们来看一下如何实现:

    // Interface
    var People = new Interface("People",["setName","getName","setAge","getAge","addHobby","getHobby","sayName","sayAge"]);
    
    var Person = function(name,age){ //implement People
      // 私有变量
      var _name,_age,_hobbys = [];
    
      this.addHobby = function(hobbys){
        _hobbys = _hobbys.concat(hobbys);
      },
      this.getHobby = function(){
        return _hobbys;
      },
      this.setName = function(name){
        if(this.checkName(name)){
          throw new Error("名字 "+name+" 不能含有数字");
        }
        _name = name;
      },
      this.getName = function(){
        return _name;
      },
      this.setAge = function(age){
        _age = age || "未设置"; 
      },
      this.getAge = function(){
        return _age;
      }
    
      this.setName(name);
      this.setAge(age);
    }
    
    Person.prototype = {
      checkName:function(name){
        re = /d/;
        return re.test(name);
      },
      sayName:function(){
        console.log(this.getName());
      },
      sayAge:function(){
        console.log(this.getAge());
      }
    
    }
    
    var person1 = new Person("Helen","20");
    person1.addHobby(['sing','drawing']);
    
    function record(person){
      Interface.ensureImplements(person,People);
      person.sayName();
      console.log(person.getHobby().toString());
    }
    
    record(person1);

    在构造函数中,属性不使用this,外部也就无法访问到这个属性,而闭包通过作用域链可以访问到这个属性,那么我们就通过闭包设置了为属性赋值的唯一入口,从而起到了严格校验这些属性的作用。

    尽管如此,在构造函数中定义方法很多时候是没必要的,因为这样每创建一个实例,就会产生一个方法的副本,这是需要内存支持的,所以在使用的过程中,如果能用上面的基本封装方法,尽量用,除非对于私有属性有非常严格的校验要求才用闭包这种方法。

    转载

  • 相关阅读:
    递归函数的写法笔记
    Spring项目中执行Java脚本
    关于秒杀的系统架构优化思路
    分布式搜索引擎Elasticsearch性能优化与配置
    分布式搜索引擎ElasticSearch+Kibana (Marvel插件安装详解)
    分布式搜索引擎Elasticsearch的查询与过滤
    Linux 下编译升级 Python
    搭建通过 ssh 访问的 Git 服务器
    分布式搜索引擎Elasticsearch的简单使用
    PHP 源码学习之线程安全
  • 原文地址:https://www.cnblogs.com/HUANGRONG888/p/6135673.html
Copyright © 2011-2022 走看看