继承

原型链继承

传统的继承方式,主要存在一种继承关系
Child.prototype.__proto__ === Parent.prototype
推导:

// 已知
const child = new Child();
child.__proto__ === Child.prototype;
Child.prototype = new Parent();
// 因为
let p = new Parent();
p.__proto__ === Parent.prototype;
// 所以
// 出现这个等式之后,就说明存在了一种继承关系!
Child.prototype.__proto__ === Parent.prototype
复制代码

原型链继承:

function Parent() {
    this.name = 'parentName';
    this.actions = [1,2];
}
Parent.prototype.getName = function() {
    console.log(this.name);
}
function Child(){};
// 原型链继承
Child.prototype = new Parent(); // 确定继承关系
Child.prototype.constructor = Child; // 做一个constructor的类型矫正。不写,则指向 Parent

// 如果 Child.prototype = Parent.prototype 则Child只能继承原型上的属性方法,不能继承实例上的属性方法

let c1 = new Child();
c1.actions.push(3); // 一旦修改,所有实例都会有影响
console.log(c1.actions); // [1,2,3]
let c2 = new Child();
console.log(c2.actions); // [1,2,3]
复制代码

问题:

  1. 如果有属性是引用类型的,一旦某个实例修改了这个属性,所有实例都会受到影响
  2. 创建 Child 实例的时候,不能传参

可用 构造函数继承 解决这两个问题。

构造函数继承

主要代码:Parent.call(this,name,actions)

function Parent(name, actions) {
    this.actions = actions;
    this.name = name;
}
  
function Child(id, name, actions) {
    this.id = id;
    Parent.call(this, name, actions);
    // 如果想直接传多个参数, 可以
    Parent.apply(this, Array.from(arguments).slice(1));
}
  
const child1 = new Child(1, "c1", ["eat"]);
const child2 = new Child(2, "c2", ["sing", "jump", "rap"]);
console.log(child1.eat === child2.eat); // false
复制代码

问题:

  1. 属性或者方法想被继承的话,只能在构造函数中定义。而如果方法在构造函数中定义了,那么每次创建实例都会创建一遍方法,多占一块内存

简单来说:重复创建方法,导致内存占用过多

组合继承

将 原型链继承 和 构造函数继承 组合

// 原型链继承 主要代码
Child.prototype = new Parent();
Child.prototype.construct = Child;

// 构造函数继承 主要代码
Parent.call(this, name, actions);
复制代码
function Parent(name,actions){
    this.name = name;
    this.actions = actions;
}
Parent.prototype.eat = function(){
    console.log(`${this.name} - eat`);
}
function Child(id) {
    this.id = id;
    Parent.apply(this,Array.from(arguments).slice(1));
}

Child.prototype = new Parent();
Child.prototype.constructor = Child;

const child1 = new Child(1, "c1", ["hahahahahhah"]);
const child2 = new Child(2, "c2", ["xixixixixixx"]);
console.log(child1.eat === child2.eat); // true
复制代码

问题:

  • 调用了两次构造函数,做了重复的操作
  1. Parent.apply(this,Array.from(arguments).slice(1))
  2. Child.prototype = new Parent()

寄生组合继承

主要是将 组合继承 中,调用第二次 构造函数 寄生在一个空函数上:

Child.prototype = new Parent();
// 变为:
let TempFunction = function(){}; // 空函数,调用多少次没多大关系
TempFunction.prototype = Parent.prototype;
Child.prototype = new TempFunction();
// 另一种写法:
Child.prototype = Object.create(Parent.prototype);
复制代码

提问:为什么以一定要通过桥梁的方式让 Child.prototype 访问到 Parent.prototype,直接 Child.prototype = Parent.prototype 不行吗?
回答:不行。
注意:Child.prototype = Parent.prototype

  1. 在 原型链继承 中引发的问题是: Child只能继承原型上的属性方法,不能继承实例上的属性方法。
  2. 在 组合继承 中引发的问题是:原型的 prototype 会随着实例的 prototype 改变而改变。(原型链继承中本身就存在这个问题)

圣杯模式

function inherit = (function(){
    var F = function(){};
    return function(Target,Origin) {
        F.prototype = Origin.prototype;
        Target.prototype = new F();
        Target.prototype.constuctor = Target;
        Target.prototype.uber = Origin.prototype;
    }
}());
复制代码

class 继承

class Parent{
    constructor(){
        this.name = 'fj';
    }
    getName(){
        console.log(this.name)
    }
}

class Child extends Parent{
    constructor(){
        super()
    }
}
复制代码

其他

鸡生蛋问题

Object instanceof Function // true
Function instanceof Object // true

Object instanceof Object // true
Function instanceof Function // true
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享