chenliqio / fe-interview

前端面试题型汇总
0 stars 0 forks source link

【JS】Day12--原型链、盗用构造函数、组合继承⭐️⭐️⭐️ #33

Open chenliqio opened 2 years ago

chenliqio commented 2 years ago

一、继承

继承主要分为:接口继承和实现继承,接口继承只继承方法签名,后者则是继承实际的方法。
实现继承是ECMAScript唯一支持的继承方式,主要通过原型链实现。

二、实现原型链

function SuperType(){
    this.property = true;
}

SuperType.prototype.getSuperValue = function(){
    return this.property; //添加一个属性
};

function SubType(){
    this.subproperty = false; //添加一个方法
}

//继承SuperType
这个赋值重写了SubType最初的原型,意味着SuperType实例可以访问的所有属性和方法,也会存在于SubType.prototype.

SubType.prototype = new SuperType(); 

SubType.prototype.getSubValue = function(){
    return this.getSuperValue;
};
 let instance = new SubType();
console.log(instance.getSuperValue()); //true,表示SubType的实例可以访问到SuperType中的方法。

实现继承的关键点,SubType没有使用默认原型,而是将其替换成一个新的对象,也就是SuperType 的实例。

这样就使SubType的实例能继承SuperType实例中的继承属性和方法。

根据原型搜索机制:读取实例上的属性时,先会读取实例,没找到,则读取实例的原型,实例原型的原型,直到搜索到该属性。
在本例子中,调用instance.getSuperValue(),搜索顺序 instance --> SubType.prototype --> SuperType.prototype。

原型链也有一定的问题:

三、盗用构造函数

可以解决原型包含引用值导致的继承问题。
基本思路:在子类构造函数中调用父类构造函数。可以使用call(),apply()以创建新的对象为上下文执性构造函数。

function SuperType(){
    this.colors = ["red","blue","green"];   //设置属性
}

function SubType(){
    // 继承SuperType
    SuperType.call(this);  //盗用构造函数的调用
}

let instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);  //["red","blue","green","black"]

let instance2 = new SubType();
console.log(instance2.colors); //["red","blue","green"]

使用call(),apply()方法,SuperType构造函数在SubType的实例创建的新对象的上下文执性,也就是新的SubType对象运行了SuperType构造函数的所有初始化代码,使得每个实例都有自己的属性。
此方法有一个优点:可以在子类构造函数中向父类构造函数传参。如下述代码:

function SuperType(name){
    this.name = name;
}

function SubType(){
    //继承SuperType并传参
    SuperType.call(this,"karen");
    // 实例属性
    this.age =18;
}
let instance = new SubType();
console.log(instance.name);  //karen
console.log(instance.age);   //18

盗用构造函数的问题

四、组合继承

结合原型链和盗用构造函数的优点。
基本思路:使用原型链继承原型上的属性和方法,通过盗用构造函数继承实例属性。

function SuperType(name){
    this.name = name;
    this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){
    console.log(this.name);
};

function SubType(name,age){
//    继承属性
SuperType.call(this,name);
this.age = age;
}

// 继承方法
SubType.prototype = new SuperType();

SubType.prototype.sayAge = function(){
    console.log(this.age);
};

let instance1 = new SubType('karen',18); 
instance1.colors.push('black');  
console.log(instance1.colors); //["red","blue","green","black"]
instance1.sayName(); //karen
instance1.sayAge();//18

let instance2 = new SubType('Bob',19); 
console.log(instance2.colors); //["red","blue","green"]
instance2.sayName(); //Bob
instance2.sayAge();//19

结果就是,创建的两个实例既有自己的属性,同时又能共享相同的方法