zoukankan      html  css  js  c++  java
  • js面向对象 继承

    1、类的声明
    2、生成实例
    3、如何实现继承
    4、继承的几种方式



    1、类的声明有哪些方式
    <script type="text/javascript">
      //类的声明
      function Animal() {
        this.name = 'name'
      }
      // es6中的class的声明
      class Animal2 {
        constructor() {
          this.name = name
        }
      }
    </script>
    2、怎么实例化这个对象
    console.log(new Animal(), new Animal2());
    3、js有几种继承方式
     
    1)
    /**
    * 借助构造函数实现继承
    */
    function Parent1() {
      this.name = 'parent1'
    }
    function Child1() {
      Parent1.call(this);
      this.type = 'child1';
    }
    console.log(new Child1());
    这样就实现了一个继承了。重点看这个Parent1.call,他改变了js运行的上下文,通过这个调用,改变了Parent1的this指向。也就是父类的所有属性都指向了子类的这个实例
    缺点:这个构造函数是有自己的原型链的,也就是有自己的prototype属性,虽然说Parent1的属性指向了Child1这个实例,但是他的prototype并没有被Child1所继承。比如说
    function Parent1() {
      this.name = 'parent1'
    }
    Parent1.prototype.say = function(){};
    

    function Child1() {   Parent1.call(this);   this.type = 'child1'; } console.log(new Child1());
    看下,是没有say方法的,说明不会继承父类的原型链,所以说,这种继承只是部分继承,如果父类还有一些方法,就拿不到



    2)
    /**
    * 借助原型链实现即成
    */
    function Parent2() {
      this.name = "parent2";
    }
    function Child2() {
      this.type = "child2"
    }
    Child2.prototype = new Parent2();
    console.log(new Child2());
    这个方法弥补第一种方式的不足,我们说任何一个构造函数都有一个prototype这个属性的,这个属性的作用是访问他的实例能访问到原型对象上。
    如图,我们看到Child2的__proto__指向的是Parent2的原型对象,prototype是Child2的一个属性,这个属性是个对象,将new Parent2()这个对象赋值给了Child2,那么new一个Child2后,访问Child2.name,在Child2里面没有找到,就会去__proto__找,也就是prototype找,也就是Parent2这个实例找,这样就实现了继承
    这个继承方式的缺点:在Parent2里面添加,this.play = [1,2,3];,然后new多个Child2的实例,发现他们都指向了同一个play。当s1改变了play,第二个对象跟着被改变了
    比如
    /**
    * 借助原型链实现即成
    */
    function Parent2() {
        this.name = "parent2";
        this.play = [1,2,3]
    }
    function Child2() {
        this.type = "child2"
    }
    Child2.prototype = new Parent2();
    
    var s1 = new Child2();
    var s2 = new Child2();
    s1.play.push(4);
    
    console.log(s1.play,s2.play);
    3)
    /**
    * 组合方式(结合构造函数 和 原型链的优点)
    */
    function Parent3 () {
      this.name = 'parent3';
    }
    function Child3 () {
      Parent3.call(this);
      this.type = 'child3'
    }
    Child3.prototype = new Parent3();

    我们再加上方法,看看是否能避免上面的问题呢

    /**
    * 组合方式(结合构造函数 和 原型链的优点)
    */
    function Parent3 () {
    this.name = 'parent3';
      this.play = [1,2,3];
    }
    function Child3 () {
      Parent3.call(this);
      this.type = 'child3'
    }
    Child3.prototype
    = new Parent3(); var s3 = new Child3(); var s4 = new Child3(); s3.play.push(4); console.log(s3.play,s4.play);

    这个时候发现就不一样了,避免了eg2的缺点,这种组合方式结合了优点,弥补了缺点,这是通常实现继承的方式

    缺点:执行了两次父类的原型链,第一次Parent2.call()。第二次 new Parent3()

    4)

    /**
    * 组合继承的优化
    */
    function Parent4 () {
      this.name = 'parent4';
      this.play = [1,2,3];
    }
    function Child4 () {
      Parent4.call(this);
      this.type = 'child4'
    }
    Child4.prototype = Parent4.prototype;
    var s5 = new Child4();
    var s6 = new Child4();

    这样父类的原型链只执行了一次,但是还剩下一个问题,s5,s6都是父类的实例,没有自己的实例,prototype里面有个contron指明是哪个的实例,而子类的prototype拿的直接是父类的prototype,所以当然拿的是父类的构造函数

    /**
    * 组合继承的优化2
    */
    function Parent5 () {
      this.name = 'parent5';
      this.play = [1,2,3];
    }
    function Child5 () {
      Parent5.call(this);
      this.type = 'child5'
    }
    Child5.prototype = Object.create(Parent5.prototype);
    Child5.prototype.constructor = Child5;

    Object.create方法创建原型对象,Parent5.prototype就是create方法的一个参数,一层一层往上找实现了继承,同时完成了继承,这个就是实现继承的完美方式

  • 相关阅读:
    [公告]Google个性化主页可以正常阅读博客园的RSS了
    致歉
    [公告]网站程序已经升级到ASP.NET 2.0
    GTF: Great Teacher Friedman
    Node.js : exports と module.exports の違い
    拨开历史的迷雾从篡夺者战争到五王之战的政经原因
    javascript模板系统 ejs v10
    window.name + postMessage实现不用代理页的跨域通信
    node.js Domain 時代のエラー処理のコーディングパターン
    鲜为人知的get,set操作符
  • 原文地址:https://www.cnblogs.com/wzndkj/p/10177267.html
Copyright © 2011-2022 走看看