js之继承实现方法

js的继承方式有很多,本文主要介绍以下几种:构造函数继承、原型链继承、组合继承、es6中的class继承这四种。

一、构造函数+call继承

构造函数一般命名时首字母大写,用来区分于普通函数,内部使用的this对象来指向即将要生成的实例对象,使用New来生成实例对象。

// 这是一个构造函数
function Animal(name) {
  this.name = name;
  this.showName = function() {
    console.log(this.name);
  };
}

function Cat(name) {
  Animal.call(this, name);
  //Animal.bind(this)(name)
  //Animal.apply(this, [name])
}

let cat = new Cat("我是一只猫");
cat.showName();
console.log(cat instanceof Animal);  // false
console.log(cat instanceof Cat);     // true

补充知识:
 call、apply、bind方法的作用都是改变函数的执行环境,第一个参数传入上下文执行环境(this),然后传入函数执行所需的参数。

优点:

  1. 可以在子类型构造函数中向Parent传递参数
  2. 避免了引用类型的属性被所有实例共享

缺点: 

  1. 只能继承构造函数中的属性和方法,而无法继承原型链上的属性和方法
  2. 实例并不是父类的实例,只是子类的实例

二、原型链继承

利用原型链来实现继承就是让父类的一个实例作为子类的原型 

// 这是一个构造函数
function Animal(name) {
  this.name = name;
  this.showName = function() {
    console.log(this.name);
  };
}

function Cat() {}

//父类的一个实例作为子类的原型
Cat.prototype = new Animal("我是一只猫");
// 注意这里new Animal()生成的父类对象并没有constructor属性,故需添加上
Cat.prototype.constructor = Cat;

let cat = new Cat();
cat.showName();
console.log(cat instanceof Animal);  // true
console.log(cat instanceof Cat);     // true

优点:

  1.  能够继承父类构造函数及其原型链上的全部属性和方法
  2. 实例是子类的实例,也是父类的实例

缺点: 

  1. 在创建实例时,不能向Parent传参

三、组合继承

组合构造函数及原型链两种继承方法,从而解决他们存在的缺点,基本思路就是使用原型链继承原型上的属性和方法,通过构造函数继承实例属性,这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。

// 这是一个构造函数
function Animal(name) {
  this.name = name;
  this.showName = function() {
    console.log(this.name);
  };
}

function Cat(name) {
  // 继承父类的属性
  Animal.apply(this, [name]); //第二次调用
}

//父类的一个实例作为子类的原型,继承父类的方法
Cat.prototype = new Animal();
// 注意这里new Animal()生成的父类对象并没有constructor属性,故需添加上
Cat.prototype.constructor = Cat;

let cat = new Cat("我是一只猫");
cat.showName();

优点:

  1. 解决了原型链继承和构造函数继承存在的问题

缺点: 

  1. 父类的构造函数被调用两次

四、class继承

利用ES6中的extends,写法更加面向对象,原理还是原型链

class Animal {
  constructor(name) {
    this.name = name;
  }
  showName() {
    console.log(this.name);
  }
}

class Cat extends Animal {
  constructor(name) {
    super(name);  //不能少,而且必须写在this前边
    this.type = "宠物";
  }
  showType() {
    console.log(this.type);
  }
}

let cat = new Cat("我是一只猫");
cat.showName();
cat.showType();

优点:

  1. 实现更简单,且不存在不能传参等问题

补充知识super :

super关键字可以当作函数 super() 使用,也可以当作对象 super 使用

1.当做函数使用

在constructor中,表示父类的构造函数,并且子类的构造函数必须执行一次super,即super(name)相当parent.prototype.constructor.call(this,name)

  constructor(name) {
    super(name);
    this.type = "宠物";
  }

super()也可写在子类的构造函数中,写在自定义函数中会报错。 

2.当做对象使用

静态方法中指向父类,在普通方法中指向父类的原型

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值