美文网首页
JS面向对象三大特征:封装、继承、多态

JS面向对象三大特征:封装、继承、多态

作者: 黄黄黄大帅 | 来源:发表于2020-09-02 11:49 被阅读0次
    封装

    把事物(属性和方法)封装在类(程序对象)中,隐藏事物的属性和方法的实现细节,仅对外公开接口。
    1.构造函数模式

    function Person(name, sex) {
            this.name = name;
            this.sex = sex;
            this.sayName = function () {
                    alert(this.name);
            };
    }
    
    var adam = new Person("亚当", 1);
    var eve = new Person("夏娃", 0);
    

    2.原型prototype封装

    function Cat(name,color){
                this.name = name;
                this.color = color;
            }
            Cat.prototype.type = "英短";
            Cat.prototype.eat = ( () => {
                alert("fish!")
            } )
              
            //生成实例
            var cat1 = new Cat('Tom', 'gray');
            var cat2 = new Cat('Kobe', 'purple');
            console.log(cat1.type); //英短
            cat2.eat(); //fish!
    

    3.声明函数模式

    • 优点
      避免了全局变量--因为存在函数作用域(函数作用域画重点,以后要考)
      按需执行--解析器读取到此处,函数并未执行,只有当你需要的时候,调用此函数即可
      提高代码重用性
    • 缺点:
      易被同名变量覆盖--因为在全局作用域下声明的变量,容易被同名变量覆盖
      立即执行--解析器读取到此处立即执行

    4.工厂模式

    function createPerson(name, sex) {
            var o = new Object();
            o.name = name;
            o.sex = sex;
            return o;
    }
    
    var adam = createPerson("亚当", 1);
    var eve = createPerson("夏娃", 0);
    
    • 优点:这种封装解决了代码重复的问题;

    • 缺点:adam和eve之间没有内在的联系,不能反映出它们是同一个原型对象的实例;

    5.闭包

    var PI = (function () {
                var _pi = 3.1415926;
                return {
                    get: function () {
                        return _pi;
                    }
                }
            }())
    
       console.log(PI.get()); //3.1415926
    
    继承

    一个对象可以使用另一个对象的属性和方法 (子类可以使用父类的属性和方法)
    1.原型链继承

    //创建自定义构造函数
    function Hqg() {
        this.name = '洪七公';
    }
    //在当前构造函数的原型链上添加属性skill
    Hqg.prototype.skill = '打狗棒'
    
    //通过自定义构造函数Hqg实例化一个对象gj
    const gj = new Hqg()
    console.log(gj.skill);//=>打狗棒
    //通过自定义构造函数Hqg实例化一个对象hr
    const hr = new Hqg()
    console.log(hr.skill);//=>打狗棒
    
    • 缺点:当父类(对象)属性或方法改变时,不同实例对象对应属性方法也会改变。

    2.借用构造函数

    //创建一个构造函数,并添加一些属性
    function Hqg() {
        this.name = '洪七公';
        this.job = '帮主';
        this.skill = ['降龙十八掌', '打狗棒']
    }
    //创建一个构造函数,并借用了Hqg的构造函数
    function Hr() {
            Hqg.call(this)
            this.name = '黄蓉';
            this.job = ['相夫', '教子']
    }
    //创建一个构造函数,并借用了Hqg的构造函数
    function Gj() {
        Hqg.call(this)
        this.name = '郭靖';
        this.job = ['吃饭', '睡觉']
    
    }
    const hr = new Hr();
    console.log(hr);
    
    const gj = new Gj();
    console.log(gj);
    
    2-1.png

    这样就避免了原型链继承中,构造函数中的属性或者方法被其他实例所改变的问题
    ⚠️:这里要注意call方法的执行顺序:

    //部分代码省略
    function Hr() {
        this.name = '黄蓉';
        this.job = ['相夫', '教子']
        Hqg.call(this)
    }
    function Gj() {
        this.name = '郭靖';
        this.job = ['吃饭', '睡觉']
        Hqg.call(this)
    }
    
    //部分代码省略
    
    4-1.png

    值会被覆盖,这个要注意!

    function Hqg(name,job,skill) {
      this.name = name;
      this.job = job;
      this.skill = skill
    }
    function Hr() {
      Hqg.call(this,'黄蓉',['相夫', '教子'],['打狗棒'])
    }
    
    function Gj() {
      Hqg.call(this,'郭靖',['吃饭', '睡觉'],['降龙十八掌'])
    }
    const hr = new Hr();
    console.log(hr);
    
    const gj = new Gj();
    console.log(gj);
    
    3-1.png

    3.组合继承
    使用原型链实现对原型对象属性和方法的继承,借用构造函数实现对实例属性方法的继承
    这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性

     function hqg(name) {
            this.name = name
            this.skill = ['打狗棒', '乾坤大挪移']
          }
          hqg.prototype.sayName = function () {
            console.log(this.name)
          }
          function Hero(name, job) {
            hqg.call(this, name)
            this.job = job
          }
          Hero.prototype.sayJob = function () {
            console.log(this.job)
          }
          Hero.prototype = new hqg()
          Hero.prototype.constructor = Hero
          var gj = new Hero('郭靖', '打老虎')
          var hr = new Hero('黄蓉', '打豆豆')
          console.log(gj)
          console.log(hr)
    

    4.寄生式继承
    寄生式继承是与原型式继承紧密相关的一种思路,它创造一个仅用于封装继承过程的函数,在函数内部以某种方式增强对象,最后再返回对象。

    function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }
    
    function hero(params) {
        const clone = object(params) //通过调用函数创建一个新对象
        clone.sayHi = () => {
            console.log('hi');
        }
        return clone
    }
    const hqg = {
        name: "洪七公",
        skill: ['降龙十八掌', '打狗棒']
    }
    const gj = hero(hqg);
    gj.name = '郭靖';
    gj.skill.push('九阴真经')
    console.log(gj);
    
    3-4.png

    5.寄生组合式继承

    function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }
    
    function hero(Children, Parent) {
        const proto = object(Parent.prototype); //返回Parent的一个副本
        proto.constructer = Children; //设置constructor指向, 因为新副本的原型对象被重写
        Children.prototype = proto; //副本作为sub的原型对象
    }
    
    function Hqg() {
        this.name = '洪七公';
    }
    Hqg.prototype.show = function () {
        console.log(this.name);
    }
    
    function Gj() {
        Hqg.call(this);
        this.name = '郭靖'
    }
    
    function Hr() {
        Hqg.call(this);
        this.name = '黄蓉'
    }
    hero(Gj, Hqg);
    hero(Hr, Hqg);
    const gj = new Gj();
    const hr = new Hr();
    gj.show(); // =>郭靖
    hr.show(); //=> 黄蓉
    
    多态

    不同对象与同一操作产生不同结果。把“想做什么”跟“谁去做”分开,把过程化的条件语句转换为对象的多态性,从而消除条件分支语句。有重写跟重载:
    重写:子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
    重载:函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。

    //非多态     
    var hobby = function(animal){
        if(animal == 'cat'){
            cat.eat()
        }else if(animal == 'dog'){
            dog.eat()
        }
    }
    
    var cat = {
        eat: function() {
            alert("fish!")
        }
    }
    
    var dog = {
        eat: function() {
            alert("meat!")
        }
    }
    
    console.log(123);
    hobby('cat'); //fish!
    hobby('dog'); //meat!
    
    //多态  
    var hobby=function(animal){
      if(animal.eat instanceof Function){
         animal.eat() 
      }
    }
    var cat={
     eat:()=>{
      console.log('miao')
     }
    }
    var dog={
     eat:()=>{
      console.log('wang')
     }
    }
    hobby(cat)// miao
    hobby(dog)// wang
    

    相关文章

      网友评论

          本文标题:JS面向对象三大特征:封装、继承、多态

          本文链接:https://www.haomeiwen.com/subject/rokbsktx.html