前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript的封装

JavaScript的封装

作者头像
wfaceboss
发布2019-04-08 10:56:29
5100
发布2019-04-08 10:56:29
举报
文章被收录于专栏:wfaceboss

一,首先,为什么要使用封装?

这是从信息的角度出发的,信息的隐藏是最终的目的,而封装只不过是实现隐藏的一种方法。

这里我们需要明白一点就是:类的定义有如下的三种方式:

(第一种)门户大开型方式       (第二种)用命令规范区别私有和公有的方式    (第三种)闭包

现在详细描述一下每一种类的定义方式:

针对第一种,门户大开类型

首先,我们来看一种情况

(1)声明一个简单的类,代码如下

代码语言:javascript
复制
 function Person(age,name) {
        this.name=name;
       
        this.age=age;
    }

  (2)实例化类+调用

代码语言:javascript
复制
var p=new Person(-10,"小明");
alert(p.age)//结果出现年龄出现负数

  从上述的运行结果中,我们可以看出程序可以正常执行,但这并符合实际,因为年龄出现 了负数,这不是我们想要的,我们需要一个能正确处理并产生与实际情况相符的解决方案。

为了能解决上述年龄出现的问题,我们可以这样做:扩展类的原型链

代码语言:javascript
复制
Person.prototype={
       checkAge:function (age) {
         if(0<age&&age<150){
             return true;
          }else {
            return false;
               }
                    }
             }

加上解决方案后,代码如下

(1)基本类

代码语言:javascript
复制
 function Person(age,name) {
        this.name=name;
        //调用方法判断验证
        if(!this.checkAge(age)){
            throw  new Error("年龄必须在0-150之间");
        }
        this.age=age;
    }

(2)年龄判断验证

代码语言:javascript
复制
  Person.prototype={
                    checkAge:function (age) {
                        if(0<age&&age<150){
                            return true;
                        }else {
                            return false;
                        }
                    }
            }

(3)调用

代码语言:javascript
复制
var p2=new Person(10,"小明");
alert(p2.age)

我们还可以给name添加一个读取验证,name为空时使用默认值 同样是扩展类的原型链

代码如下,

代码语言:javascript
复制
 Person.prototype["getName"]=function () {
                return this.name||"我是默认的";
            }
//调用

总结一下:当类被定义为门户大开类型时会出现与实际不符合的情况 ,虽然我们可以加在类上扩展原型类加验证方法解决,但是这样会使类变得臃肿。

针对第二种,用命名规范区别私有和公有

步骤如下,

(1)定义类 在类中定义变量(私有和公有变量)+验证方法的调用

代码语言:javascript
复制
//用命名规范来区别私有和公有
    function Person(name,age,email) {
        //定义私有变量

        this._name;//私有
        this.setName(name);//只是方法的调用,方法中有验证,而不是在类中验证

        this._age;//私有
        this.setAge(age);
         this.email=email;//公有的
    }

(2)在类的原型上面 扩展赋值方法

代码语言:javascript
复制
Person.prototype={//直接扩展至原型上,可以在本类的内部使用this调用
        setName:function (name) {
        this._name=name;
        },
        setAge:function (age) {
            //需要做判断符号实际情况
            if(age>0&&age<150){//验证不在类中,类不会变的臃肿
                this._age=age;
            }else {
                throw  new Error("年龄必须是在0到150范围内")
            }
        }

    }

(3)应用

代码语言:javascript
复制
var text1=new Person("测试",-10,"qq.com");
 alert(text1._age)//-10 程序会报错 这是我们想要的(说明验证是对的)
代码语言:javascript
复制
  var p2=new Person("测试2",10,"qq.cpm");
    alert(p2._age)//程序正常运行 达到我们的目标

总结一下:在类的定义是使用命名规范来定义私有变量和公有变量,并将验证方法和赋值方法扩展到本类的原型链上,在类中调用方法即可(会有返回值),这样不会导致类的臃肿。

针对第三种,闭包实现封装

这种方式有点像高级语言,在定义类是使用get,set方法实现数据的操作

(1)定义一个基本类(变量+操作变量的方法)

代码语言:javascript
复制
   function Person(name,age,email) {
        //(1)声明变量和对变量进行操作的get和set方法
        this.email=email;//公有变量

        //get方法
        this.getName=function (name){
            return this.name;//为什么是this调用呢?请看set方法
        }
        this.getAge=function (age){
            return this.age;
        }
        //set方法  这里相当于在类上的扩展
        this.setName=function (name) {
            this.name=name;//Person.prototype.name  这里写明了get中this的写法的来源
        }
        this.setAge=function (age) {
            if(age>0&&age<150){
                this.age=age;//Person.prototype.name  这里写明了get中this的写法的来源
            }else {
                throw  new Error("年龄必须是在0到150范围内");
            }
        }


        //(2)写一个构造函数 做初始化  实现闭包  确保set是在get之前的,不然get时会出现错误
        this.init=function () {
         this.setName(name);
         this.setAge(age);
        }
        this.init();//显示调用
    }

(2)应用

代码语言:javascript
复制
var p=new Person("text",-10,"qq.com");
    alert(p.age)//程序由于不符合实际而被阻断,符合要求

 注:额外的闭包写法   var 方式

代码语言:javascript
复制
 var  _sex="M";
        this.getSex=function () {
             return _sex;
        }
        this.setSex=function () {
               _sex=sex;
        }

总结一下:

(1)这里只是函数和属性的简单封装,还有更为复杂是业务需要封装,使用get和set方法时,需要一个构造函数用于两者先后顺序的初始化实现闭包,之后显示调用,确保set是在get之前的。

(2)闭包的实现,是通过get和set实现的,this.方式赋值时没有暴露在外面而是通过get,set方法实现闭包。

二,静态化

普通属性和函数是作用在对象上到,而静态函数是定义到类上的。

第一种静态函数的写法 :写在类上

(1)首先,定义一个简单的类,例如

代码语言:javascript
复制
 function Person(name,age) {
        this.name=name;
        this.age;age;
        this.showName=function () {
            alert(this.name);
        }
    }

(2)定义一个写在类上的方法,Person.add --》(类.函数)或者(类.属性),例如

代码语言:javascript
复制
 Person.add=function (x,y) {
        return x+y;
    }

(3)应用

代码语言:javascript
复制
alert(Person.add(10,20));//结果为30

总结一下,该种定义方式有点类似于高级语言的静态类,使用与高级语言的相同通过类直接调用。

第二种静态函数的写法 :使用类中类的方式完成每一个对象全拥有当前类中相同的属性和函数 。注意:  类中类的方式是一次性赋值的

(1)类的定义格式如下

代码语言:javascript
复制
var cat=(function () {
        //私有静态属性
         var AGE=1;
         function add(x,y) {
             return x+y;
         }


         return function () {//类中类  return返回的类中持有与上面类中相同的属性与函数  则共同的AGE和add称为静态属性和静态函数
             this.AGE=AGE;
             this.add=function (x,y) {
                return add(x,y)
             }
         }
    })()//实例化cat,实质是通过return实例化的

(2)应用

代码语言:javascript
复制
 alert(new cat().add(1,3))//4
  alert(new cat().AGE)//1

总结一下:从上面的代码格式中我们不难看出在一个类中定义有私有的属性和方法,与一个返回可以初始化本类私有静态属性和方法的类,该类我们称为类中类。当我们实例化外层类时实质上是通过该类内部的类return实例化的。

封装的优点:

代码语言:javascript
复制
(1)保护内部数据完整性是封装一大用处
(2)对象的重构变得轻松,(如果没有封装你敢动正在运用的代码吗?) 答案肯定是不敢的。
(3)化模块间的耦合

弊端:
代码语言:javascript
复制
(1)私有的方法会变得难以进行单元测试
(2)使用封装意味着与复杂的代码打交道
(3)最大问题封装在JavaScript中很难实现  除非运用自如,否则到处封装,使测试变得困难。


以上只是学习的初步理解,不好还希望多多理解。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-10-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档