面向对象2

引言

1、所有的编程语言按照数据类型大体可以分为两类:

  • 一类是静态类型语言,另一类是动态类型语言。 静态类型语言在编译的时候呢,我们已经确定的变量的类型。而动态类型语言。它的变量类型要到程序运行的时候,等待变量被赋予某一个值之后,才会具有某种类型;
  • 在js当中,当我们对一个变量赋值的时候,我们不需要考虑它的的类型。因此,JavaScript是一门典型的动态类型的类型语言
    var duck={
        duckSing:function(){
            console.log('嘎嘎嘎');
        }
    }
    var chicken={
        duckSing:function(){
            console.log('嘎嘎嘎');
        }
    }
    var choir=[];
    var joinChoir=function(animal){
        if(animal&&typeod(animal.duckSing)==='function'){
            choir.push(animal);
            console.log('恭喜加入合唱团');
        }
    }

2、定义类的基本写法

2.1使用构造函数来定义类

  • JavaScript推荐使用构造函数来定义类。就是写一个鬼知道(constrctor),然后new 关键字对这个构造函数 进行实例化从而得到一个对象。
  • 例如:我需要定义一个person infor的类别。他有这样的属性。name(姓名)gender(性别)。这样的字段
    function (){
        this.name'';//姓名
        this.gender=0//性别:0 未知,1男,2女
    }
    var p=new PersonInfo();
    p.name='哈哈';
    p.gender=0;

2.2编写方法

  • 定义类之后,即可为它编写方法,具体的办法是在构造函数的原型当中增加函数。比如说我们给personInfor增加一个。Sayhi的方法。
     function (){
        this.name'';//姓名
        this.gender=0//性别:0 未知,1男,2女
    }
    PersonInfo.prototype.sayHi=function(){
        var result='你好,我叫'+this.name+',我的性别是'+this.gender;
        console.log(result);
    }

3、基本写法的改进

3.1使用命名空间来避免全局名称的污染

  • 为了避免全局名称的污染,可以使用命名空间机制。虽然JavaScript没有命名空间的语法,但是我们可以通过一些基础的方法去模拟这样的一个操作。
    var JSnamespace=window.JSnamespace||{};
    JSnamespace.PersonInfo=function(){
        this.name'';//姓名
        this.gender=0//性别:0 未知,1男,2女
    }
    JSnamespace.PersonInfo.prototype={
        sayHi:function(){
            var result='你好,我叫'+this.name+',我的性别是'+this.gender;
            console.log(result);
        }
    }

3.2改进构造函数

3.2.1构造函数参数、
  • 一般来说我们可以通过构造函数添加参数的方法,来简化对象的创建和赋值。
    var JSnamespace=window.JSnamespace||{};
    JSnamespace.PersonInfo=function(name,gender){
        this.name=name;//姓名
        this.gender=gender||0//性别:0 未知,1男,2女
    }
    JSnamespace.PersonInfo.prototype={
        sayHi:function(){
            var result='你好,我叫'+this.name+',我的性别是'+this.gender;
            console.log(result);
        }
    }
    // 有两处缺陷。
    // 1.随着对这个类的改进可能会增加更多的实例的字段。也可能会导致参数列表的频繁改动。
    //2.还有就是⾮常依赖这个参数的顺序。万⼀传参时某个参数的顺序写错。就会有数据问题。
3.2.2拷贝构造函数
  • 为了解决上述的亮点不足,且为的对象的赋值。推荐使用"拷贝构造函数"这种构造函数写法。
    // 第一种
    JSnamespace.PersonInfo=function(params){
        // 当没传参数时,我们将它当成空对象
        params=params||{};
        this.name=params.name;//姓名
        this.gender=params.gender||0//性别:0 未知,1男,2女
    }
    // 第二种
    JSnamespace.PersonInfo=function(params={}){
        // 当没传参数时,我们将它当成空对象
        this.name=params.name;//姓名
        this.gender=params.gender||0//性别:0 未知,1男,2女
    }
  • 我们可以这样去实例化
    var p=new JSnamespace.PersonInfo({'name':'aaa'})

3.3使用文档注释来改进代码的可读性。

         / @class 
          JavaScript的命名空间
          @abstract 
         /
        var JSnamespace = window.JSnamespace || {};
        /
          @namespace:JSnamespace
          @class :JSnamespace.PersonInfo
          个人信息、构造函数的类
          @params {object} 个人信息对象
          @a {string} 测试
         /
        JSnamespace.PersonInfo = function(params = {}, a) {
            // 当没传参数时,我们将它当成空对象。
            this.name = params["name"]; //姓名
            this.gender = params["gender"] || 0; //性别 :0 未知,1男,2女
            // this.job=job||'无业';
        };
        /
          个人信息、构造函数的类的原型属性
          
         /
        JSnamespace.PersonInfo.prototype = {
            /
              获取打招呼的 字符串
              
              @return {string} 返回自我介绍的字符串
             /
            sayHi: function() {
                var result = '你好,我叫' + this.name + ',我的性别是' + this.gender;
                return result;
            }
        }
        // 文档注释的说明
        // @class 表示这是一个类
        // @abstract 该类(或方法)是抽象的。

3.4枚举

  • 之前呢,我们对于性别处理的时候,我们使⽤的是直接使⽤数值代码来表示的。数值代码可读性⽐较差,并且 不太好维护。很多编程语⾔都有定义枚举类型的语法。来去解决这个问题。虽然 js 没有定义枚举类型的语法。 但是我们可以通过⼀些办法来去模拟这个操作。⽐如说,我们定义⼀个 Object 的变量。其中的字段呢就是各种 各样的枚举值。
    /@enum
      性别代码 枚举类
    /
    JSnamespace.GenderCodr={
        /未知/
        'UNKMOWN':0,
        // 男
        'MALE':1
        // 女
        'FEMAILE':2
    }
  • 然后改进构造函数使用枚举值。
    JSnamespace.PersonInfo = function(params = {}) {
        // 当没传参数时,我们将它当成空对象。
        this.name = params["name"]; //姓名
        this.gender = params["gender"] ||JSnamespace.GenderCodr.UNKMOWN;
    };
    var p=new JSnamespace.PersonInfo({
        'name':'张三',
        'gender':JSnamespace.GenderCodr.MALE
    })
    JSnamespace.PersonInfo.prototype = function() {
        getGenderApp: function() {
            var result = '';
            if (JSnamespace.GenderCode.MALE == this.gender) {
                result = '先⽣';
            } else if (JSnamespace.GenderCode.FEMAILE == this.gender) {
                result = '⼥⼠';
            }
                return result;
        },
        sayHi: function() {
            var result = '您好,' + this.name + this.getGenderApp() + ',欢迎光临红浪漫。';
            return result;
        }
    }

4.封装

  • 封装(encapsulation):封装是将程序按照⼀定的逻辑分成多个相互协作的部分。并且对外界提供稳定的部分,我 们要对外界暴露出来⽐较稳定的这⼀部分的接⼝。将改变的部分隐藏起来,隐藏在内部。外界只能通过暴露出 来的部分。想这个对象发送操作请求,从⽽享受对象提供出来的⼀些服务。我们不需要去关⼼。对象内部是如 何阳区运作的.
  • 封装性体现在 2 个⽅⾯:
    1.对外隐藏实际的细节,只能⽤专⻔约定的⽅法去操作。
    2.对内能实 现变量的共享,⽤于实现⼀些⽐较复杂的逻辑。

4.1私有静态变量

  • 在 js 中可以使⽤"⽴即执⾏函数"(⾃执⾏函数)来隐藏私有变量,这个⽅法很适⽤于在对象的封装上。
        var JSnamespace = window.JSnamespace || {}; 
        // 枚举 
        JSnamespace.GenderCode = {
            /未知/
            UNKNOWN: 0, 
            // 男   
            MALE: 1, 
            // ⼥   
            FEMAILE: 2
        };
        JSnamespace.PersonInfo = function(params = {}) {
            // 当没传参数时,我们将它当成空对象。   
            this.name = params["name"]; //姓名   
            this.gender = params["gender"] || JSnamespace.GenderCode.UNKNOWN;
        };
        (function() {
            /    
               @static @private 
             /
            var H_HelloWord = "你好";
            JSnamespace.PersonInfo.prototype = {
                getGenderApp: function() {
                    var result = "";
                    if (JSnamespace.GenderCode.MALE == this.gender) {
                        result = "先⽣";
                    } else if (JSnamespace.GenderCode.FEMAILE == this.gender) {
                        result = "⼥⼠";
                    }
                    return result;
                },
                sayHi: function() {
                    var result = H_HelloWord + this.name + this.getGenderApp() + ",欢迎光临红浪漫。";
                    return result;
                }
            };
        })();
  • 将私有变量与 prototype ⽅法。绑定代码都放到⽴即执⾏函数中。这样的写法的优点:
    • 1.实现了封装性。私有变 量只能在这个⽴即执⾏函数的内部去使⽤,不会暴露到外部。
    • 2.实现了变量的共享。可以使我们的 sayHi()⽅法 能访问到私有静态变量。 H_HelloWord
    • 3.同⼀个类的⽅法。定义都写在⼀个⼤括号⾥⾯。提⾼代码的可读性。 按照⾯向对象编程的定义,H_HelloWord 实际上是⼀个静态私有变量.

4.2私有成员函数

    (function() {
        /
         @static @private
        /
        var H_HelloWord = "你好";
        var getGenderApp = function(gender) {
            var result = "";
            if (JSnamespace.GenderCode.MALE == gender) {
                result = "先⽣";
            } else if (JSnamespace.GenderCode.FEMAILE == gender) {
                result = "⼥⼠";
            }
            return result;
        };
        JSnamespace.PersonInfo.prototype = {
            sayHi: function() {
                var result = H_HelloWord + this.name + this.getGenderApp() + ",欢迎光临红浪漫。";
                    return result;
            }
        };
    })();

4.3公开静态成员

  • 静态成员是属于整个类的,⽽不是某⼀个对象实例的。因此有些时候呢,是需要将静态成员公开给外部去使⽤ 的。对于⼤多数的⾯向对象的编程语⾔,我们可以使⽤"类.成员⽅法"。这样的语法来去使⽤静态成员。
    var JSnamespace = window.JSnamespace || {};
    / @enum 
      性别代码  枚举类
     /
    JSnamespace.GenderCode = {
        / 未知 /
        UNKNOWN: 0,
        // 男   
        MALE: 1,
        // ⼥   
        FEMAILE: 2
    };
    JSnamespace.PersonInfo = function(params = {}) {
        // 当没传参数时,我们将它当成空对象。   
        this.name = params["name"]; //姓名   
        this.gender = params["gender"] || JSnamespace.GenderCode.UNKNOWN;
    };
    (function() {
        var say_hi_word = "你好";
        JSnamespace.PersonInfo.getSayHiWord = function() {
            return say_hi_word + 'a';
        };
        JSnamespace.PersonInfo.setSayHiWord = function(word) {
            say_hi_word = word;
        };
    })();

5.继承

  • 继承(inherit),也称之为叫派⽣。继承关系中,被继承的称之为⽗类或者(基类)。从⽗类继承⽽来的,被称之 为⼦类(或者派⽣类)。继承是保持对象之间的差异性的同时共享对象相似的属性的复⽤。
  • 被继承的类总是有⼀些他所抽象的那⼀类事物的共同特点。继承实际上是提供了复⽤。只要从⼀个类继承,我 们就拥有了这个类的所有的⾏为或者属性。语义上的继承那表示是⼀种是什么is-a关系。
    // 使⽤call和apply 做继承 
    // ⽗类.call(⼦类,'⼦类实例化所需的参数1','⼦类实例化所需的参数2',…………) 
    // ⽗类.apply(⼦类,['⼦类实例化所需的参数1','⼦类实例化所需的参数2',…………])     
    var JSnamespace = window.JSnamespace || {};
    / @enum
      性别代码  枚举类 
     /
    JSnamespace.GenderCode = {
        / 未知 /
        UNKNOWN: 0,
        // 男             
        MALE: 1,
        // ⼥             
        FEMAILE: 2
    };
    // ⽗类         
    JSnamespace.PersonInfo = function(params = {}) {
        // 当没传参数时,我们将它当成空对象。             
        this.name = params["name"]; //姓名             
        this.gender = params["gender"] || JSnamespace.GenderCode.UNKNOWN;
        // this.a=a;         
    };
    (function() {
        var say_hi_word = "你好";
        JSnamespace.PersonInfo.getSayHiWord = function() {
            return say_hi_word;
    }
        JSnamespace.PersonInfo.setSayHiWord = function(word) {
            say_hi_word = word;
        }
    })();
    //添加 雇员信息类,它继承⾃PersonInfo(个⼈信息)类,         
    JSnamespace.Employee = function(params = {}) {
        // JSnamespace.PersonInfo.call(this,JSnamespace.PersonInfo); 
        JSnamespace.PersonInfo.call(this, {
            "name": params['name'],
            "gender": params['gender']
        });
        this.email = params['email'];
    };
    var e = new JSnamespace.Employee({
        'email': '417458052@qq.com'
    })

多态

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lx610321

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值