js继承的几种方式

看了w3school 上的ECMAScript 继承机制实现讲的几种方式,感觉还是有点乱,所以还是想再详细理一下继承的几种方式,分享给大家

1.构造函数继承

 //构造函数继承
  function Animal() {
      this.type = 'animal';
      this.play = function () {
        console.log('play')
      }
  }
  function Cat() {
      Animal.call(this);//关键代码
      this.name = 'cat'
      this.play = function () {
        console.log('play')
      }
  }

  console.log(new Cat(),new Animal());

查看打印结果,Cat确实继承了Amimal的属性和方法,那这个实现原理是怎么样的,看关键代码(call,apply不清楚了可以看下call和apply的使用),这里调用了父级Animal函数,然后让父级函数本身的this指向变成了子级Cat的实例对象,相当于父级的所有的属性和方法在子级Cat函数里再次声明了一次。但是这种方式也有弊端,看代码

 Animal.prototype.eat = function () {
     console.log('I can eat')
  }

再次打印结果

可以发现,当我们在原型链上添加属性和方法时,子级并没有继承父级的属性和方法

总结:构造函数继承只能继承在构造函数里声明的属性和方法,不可以继承父级原型链上的属性和方法

2.原型链继承 (之前讲过一章关于原型propotype的应用

   //原型链继承
  function Animal() {
      this.type = 'animal';
      this.play = function () {
        console.log('play')
      }
  }
  function Cat() {
      this.name = 'cat'
  }
  Animal.prototype.eat = function () {
    console.log('i can eat')
  }
  Cat.prototype = new Animal();
  console.log(new Cat(),new Animal());

这种方式可以继承原型链上的属性,但是同样有弊端

 function Animal() {
      this.type = 'animal';
      this.play = function () {
        console.log('play')
      }
      this.body = ['head','arm']

  }
  function Cat() {
      this.name = 'cat'
  }

  Cat.prototype = new Animal();
  var cat1 = new Cat();
  var cat2 = new Cat();

  cat1.body.push('foot')
  console.log(cat1,cat2);

查看打印结果可以 ,我new了两个实例对象后,改变其中一个对象的属性,另外一个对象也会受到影响

总结:使用原型链继承,会导致有一个实例对象的属性发生改变时,会被其他实例对象所共享

3.组合继承

组合继承其实就是讲上述两种方式结合在一起

   //组合继承
  function Animal() {
      this.type = 'animal';
      this.play = function () {
        console.log('play');
      }
      this.body = ['head','arm'];

  }
  function Cat() {
      Animal.call(this);//Animal函数调用一次
      this.name = 'cat';
  }

  Animal.prototype.eat = function () {
    console.log('i can eat');
  }
  Cat.prototype = new Animal(); //Animal函数调用一次
  var cat1 = new Cat();
  var cat2 = new Cat();
  cat1.body.push('foot')
  console.log(cat1,cat2);

观察上述代码,显然Animal被调用两次,这无疑中增加了内存消耗

改进:

  将Cat.prototype = new Animal();  替换成下面两行
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

将Cat原型对象设置成Animal的原型对象,通过实例对象的_proto_可以一层层往父级查找属性和方法,Cat.prototype的constructor还是Animal,所以我们需要再次把他赋值成Cat

总结:组合方式排除了构造函数继承和原型链继承的弊端,是JS中最常用的继承模式了

4.class继承 

class 是ES6新增的语法  

  class  Animal{
    constructor() {
        this.name = 'test';
    }
    play() {
          console.log('animal')
    }
  }

  class Cat extends Animal{
      constructor(type) {
        super(type);
        this.type ='cat'
      }
  }
  var cat = new Cat();
  console.log(cat.name)

直接class 创建一个类,使用extends来继承。

总结:最方便快捷的继承方式,但是仅支持ES6及以上版本,所以要考虑兼容性问题,其他没毛病

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值