js继承——至少说出这三种

187 阅读2分钟

第一种:借助构造函数继承

代码

 function Father (x, y) {
    this.x = x;
    this.y = y;
 }
 Father.prototype.show = function () {
    console.log('父类原型链上的方法');
 }
 function Son() {
    Father.call(this, 1, 2)
 }
 
 let son = new Son();
 console.log(son)

构造函数继承

  1. 可以看到,子类Son继承到了父类Father构造函数中的属性,但是并未继承到父类原型链·Father.prototype上的方法show
  2. Son的多个实例对象不会互相影响,他们的属性是独立的。

第二种:原型链继承

代码

function Father (x, y) {
    this.x = x;
    this.y = y;
    this.arr = [1,2,3]
 }
 Father.prototype.show = function () {
    console.log('父类原型链上的方法');
 }
 
 function Son () {}
 Son.prototype = new Father(1, 2);
 console.dir(Son)

我们打印子类Son看看

原型链继承

  1. 子类Son不仅继承到了父类构造函数中的属性,也继承到了父类原型链上的方法show
  2. 关系:
    Son.prototype === Father.prototype // true

原型链继承

  1. 由上图也可以看出,原型链继承的方式,Son.prototypeconstructor并不是指向Son本身,而是指向它的父类Father

  2. 子类Son的继承情况

    let son1 = new Son();
    let son2 = new Son();
    console.log(son1, son2)
    son1.x = 111; // 修改一个实例的基本类型属性,是否影响其他实例?
    son1.arr.push(4); // 修改一个实例的引用类型属性,是否影响其他实例?
    console.log(son1, son2)

修改实例属性看影响

  • 结论:
    • 修改实例的基本类型属性,子类实例自动添加同名属性,不会影响到Son的基本类型属性。也不会影响其他实例。
    • 修改实例的引用类型属性,直接修改其父类Son的相应的引用类型属性,自然其他实例的相应引用类型属性也发生改变。

第三种:组合继承

代码

function Father (x, y) {
    this.x = x;
    this.y = y;
    this.arr = [1,2,3]
}
Father.prototype.show = function () {
    console.log('父类原型链上的方法');
}
function Son (m) {
    this.m = m;
    Father.call(this, 1, 2) // 在这里传值
}
Son.prototype = new Father();
Son.prototype.constructor = Son;
console.dir(Son)

打印一下Son

组合继承

  1. 手动将constructor指回Son
Son.prototype.constructor === Son // true
  1. Son继承了Father构造函数中的属性和原型链上的方法。
Son.prototype = new Father();
Son.prototype.__proto__ ==== Father.prototype; // true
  1. 子类Son的继承情况
    let son1 = new Son('第一个实例');
    let son2 = new Son('第二个实例');
    console.log(son1, son2)
    son1.x = 111; // 修改一个实例的基本类型属性,是否影响其他实例?
    son1.arr.push(4); // 修改一个实例的引用类型属性,是否影响其他实例?
    console.log(son1, son2)

修改前:

修改实例属性看影响
修改son1后:
修改实例属性看影响

  • 结论:
    • 通过组合继承后的子类Son经过实例化后得到的实例之间相互独立。可以实现多继承。