IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 彻底搞懂原型链三种继承及ES6的Class继承 -> 正文阅读

[JavaScript知识库]彻底搞懂原型链三种继承及ES6的Class继承

原型继承

优点:同一个原型对象

缺点:不能修改原型对象,会影响所有实例

 function Animal(){
         this.type = "动物"
      };
      
      function Cat(name,color){
         this.name = name;
         this.color = color;
      };
      Cat.prototype = new Animal();
      var c1 = new Cat('x','白色');
      var c2 = new Cat('t','黑色');
      c1.type   //'动物'

可以看出Cat实例继承了Animal的type属性

拓展:

function Animal(){   //动物对象   
         this.type = '动物'
      };
      function Cat(name,color){   //猫对象  
         this.name = name;
         this.color = color;
         this.type='我是猫';
      };
      Cat.prototype = new Animal();  //猫的原型对象指向了动物函数
      var cat1 = new Cat("小黄","黄色");
      var cat2 = new Cat("小黑","黑色");
      console.log(cat1.type); // '我是猫'
      console.log(cat2.type); // '我是猫'
      //想获取Animal成员值
      console.log(cat1.__proto__.type); //'动物'
      console.log(cat2.__proto__.type); //'动物'

从上面代码块的输出可以看出,如果当前构造器和父级Animal里面都有的属性,cat1.type取到的是当前构造器Cat里面的type属性,如果想要拿到原型对象Animal里面的,必须通过cat1.__proto__.type取到。如果用cat1.__proto__.type='xx'来修改原型对象上的属性,那么所有实例都会受到影响,这也是原型继承的一大弊端。

当我们访问一个原型对象的属性时,__proto__是一级级来获取,当继承关系很复杂,不知道究竟是怎么样继承关系,只能一层一层向上查找。

构造函数继承

优点:不存在修改原型对象影响所有实例,各自拥有独立属性

缺点:父类的成员会被创建多次,存在冗余且不是同一个原型对象

★通过call/apply只能拷贝成员,原型对象不会被拷贝。

 function Animal(){  
         this.type = "动物"
     };
     function Cat(name,color){       
         Animal.apply(this);   //将Animal对象的成员复制到Cat对象上
         this.name = name;
         this.color = color;
     };
     var cat1 = new Cat("小黄","黄色"); 
     var cat2 = new Cat("小黑","黑色");
     cat1.type = '我是小黄';
     cat2.__proto__.type = '我是动物';
     console.log(cat1.type); //'我是小黄'  cat1被修改
     console.log(cat2.type); //"动物"

从上面代码块的输出可以看出,由于是有apply()改变this的指向,相当于将Animal对象的成员复制到Cat对象上。当cat2通过__proto__改变了父类Animal的type属性时,不会影响自身的type的属性。只能通过cat1.type = ‘’来改变,此时Animal和Cat并不是指向同一个原型对象,每次创建一个子类父类成员都要被创建一次,存在冗余,这也是构造函数继承的一大弊端。

组合继承

有没有一种方法既能规避原型继承的子类实例的属性容易受到原型对象的影响,以及构造函数使子类和父类不指向同一个原型对象,存在冗余的缺陷呢?

function Animal(){   
      this.type = '动物'
   };
  Animal.prototype.eat = function(){console.log('吃猫粮')};  
  function Cat(name,color){  
     this.name = name;
     this.color = color;
     Animal.call(this); 
  };
  Cat.prototype = new Animal();  
  var cat1 = new Cat("小黄","黄色");
  var cat2 = new Cat("小黑","黑色");
  cat1.type = '我是小黄';  //修改当前构造器中的属性
  cat2.__proto__.type = '我是动物';//修改了原型对象的值,但并不影响cat1,cat2的值
  console.log(cat1.type); //'我是小黄'  //原型对象的值变化,并不影响构造函数值
  console.log(cat2.type); //'动物'
  console.log(cat2.__proto__.type);  //'我是动物
  cat1.eat(); //还可以调用原型对象中eat()方法
   

通过上面代码块的输出可以看到,cat2.__proto__.type = '我是动物'对原型属性进行修改,并没有影响到实例cat2里面的type,说明子类的实例不会受父类原型上的对象属性的改变而影响。Cat.prototype = new Animal()让他们属于同一个原型对象,这样在cat的实例对象里面仍然是可以取到在父级Animal的原型对象上的eat()方法,这样解决了构造函数继承方法种由于子类和父类不指向同一原型对象,每次创建一个子类父类成员都要被创建一次,存在冗余的弊端。

Class继承

class A {
        constructor(){
            this.a = 'a';
        }
    };


    class B extends A{   //表示通过extends关键字 ,继承A类所有的属性和方法
        constructor(){
            super();  //表示父类的构造函数
            this.b = 'b';
        }
    };

    var a = new A();
    var b = new B();
    b.a     //"a"

B类通过extends关键字,继承了A类所有的属性和方法。

子类必须在constructor种调用super()方法,否则新建实例会报错。super既可以当作函数用,也可以当作对象用,作为函数使用时,代表父类父类的构造函数。ES6要求,子类的构造函数必须执行一次super函数。

那么super作为对象是用的具体实例是怎么样的呢?

class A{
    p(){
        return 2;
    }
}

class B extends A{
    constructor(){
        super();
        console.log(super.p());//2   super此时作为对象,其实就是A类
    }
}

let b = new B;

此时super.p()的super就是作为对象,其实就相当于时classA。

拓展:

class A {
        constructor(x,y){
            this.x = x;
            this.y = y;
        }
        toString(){
            return this.x
        }
    };

    class B extends A{   //表示通过extends关键字 ,继承A类所有的属性和方法
        constructor(x,y,b){
            super(x,y);  //表示父类的构造函数
            this.b = b;
        }
    };
   
    let b = new B('333','444','abc');
    b.x    //'333'
    b.y    //'444'
    b.toString()    //'abc'

super()里面需要加参数才能将数据传给继承了A类的属性及方法。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 12:53:24  更:2022-03-06 12:54:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:28:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码