Skip to content

js 继承

TIP

ES5 和 ES6 继承的区别
ES5 继承:是先创建子类的实例,再将父类的属性绑定到子类的 this 上。
ES6 继承:是先创建父类的实例对象 this,再用子类的构造函数修改 this,因为子类没有自己的 this,所以必须调用父类的 super()方法,否则新建实例会报错。

1. 构造函数继承

使用 call 来改变父类 this 的指向,来调用父类的属性和方法。 缺点:只能继承父类实例上的属性和方法,不能继承父类原型上的属性和方法

js
//构造函数继承
let Parent = function (name) {
  this.name = "baba";
};
let Child = function () {
  Parent.call(this);
  this.age = 28;
};
let child1 = new Child();

2. 原型链继承

子类的原型指向父类的实例来继承父类的属性和方法 优点:可以继承父类的实例方法和属性,也能继承父类原型上的属性和方法 缺点:对于引用类型改变,多个实例会相互影响。 创建子类的实例时不能像父类的构造函数中传递参数。

js
let Parent = function () {
  this.name = ["我是父类的属性name,我是个数组,引用类型"];
  this.age = 50;
};
Parent.property.say = function () {
  console.log("我是父类property上的方法。");
};
let Child = function () {
  this.role = "我是儿子";
};
Child.property = new Parent();
let child1 = new Child();
let child2 = new Child();
child1.name[0] = "我是child1我改变了名字";
child1.age = 28;
child2.name[0] = "我是child2我也改了名字";
child.age = 20;
console.log(child1);
/**
{
    name:[我是child2我也改了名字],
    age:28,
    role:"我是儿子",
    say:function(){console.log("我是父类property上的方法。");}
}
**/
console.log(child2);
/**
{
    name:[我是child2我也改了名字],
    age:20,role:"我是儿子",
    say:function(){console.log("我是父类property上的方法。");}
}
 **/

3. 组合继承(原型链和构造函数组合继承)

将原型链继承和构造函数组合到一起继承,通过原型链来继承父类原型上的属性和方法,通过构造函数继承父类实例的属性和方法。 缺点:使用子类创建实例的时候,原型中会存在两份相同的属性和方法。

js
let Parent = function (name) {
  this.name = ["父类"];
};
Parent.prototype.say = "父类原型上的属性";
let Child = function () {
  Parent.call(this);
  this.childName = "子类";
};
Child.prototype = new Parent();
let child1 = new Child();
child1.name[0] = 222;
console.dir(child1);
/***
 * 结果为
 {
    childName:"子类",
    name:[222],
    [[Property]]:{
        name:['父类'],
        say:'父类原型上的属性'
    }
 }
* */

4. class 继承

class 创建一个父类,然后通过 extends 继承父类,在子类的 constructor 调用 spuer()

js
class Parent {
  constructor() {
    this.name = "我是父类继承过来的属性";
  }
  say() {
    console.log("我是父类的方法");
  }
}
class Child extends Parent {
  constructor() {
    super();
    this.age = 24;
  }
}
let child1 = new Child();