最近在准备面试,js继承真的好乱鸭鸭鸭鸭,整理一下~希望可以记得!
(参考:https://blog.csdn.net/caijixin/article/details/78295676
https://juejin.im/entry/5bcb2f695188255c2f425251)
1. 借用构造函数继承
- 通过call、apply方法,使用父类的构造函数来增强子类实例,等同于复制父类的实例给子类(不使用原型)
- SuperType.call(this);创建子类实例时调用SuperType构造函数,于是SubType的每个实例都会将SuperType中的属性复制一份。
function SuperType() {
this.colors = ["red","blue","green"];
}
function SubType() {
//继承了SuperType --重新创建SuperType构造函数属性的副本
SuperType.call(this);
}
ar instance1 = newe SubType();
instance1.colors.push("black");
console.log(instance1.colors); //"red,blue,green,black"
缺点:
- 只能继承父类的实例属性和方法,不能继承原型上的属性或方法
- 每个子类都有父类实例的副本,没能做到复用,影响性能
优点
- 可以传参,SuperType.call(this,"Nicholas");
2.原型链方法
- 利用原型链来实现继承,超类的一个实例作为子类的原型
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){}
SubType.prototype = new SuperType();
SubType.prototype.constructor=SubType;
- SubType.prototype.constructor=SubType;如果没有这句SubType.prototype.constructor会指向SuperType
缺点:
- 如果父类包含引用类型的属性,那么子类所有实例都会共享该属性。
- 在创建子类型的实例时,不能向超类的构造函数中传递传递参数
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){}
SubType.prototype = new SuperType();
SubType.prototype.constructor=SubType;
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green,black"
3.组合继承方法
- 组合上面两种方法就是组合继承方法。用原型链继承实现对原型属性和方法的继承,借用构造函数继承方法实现对实例属性的继承。
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
// 继承属性
// 第二次调用SuperType()
SuperType.call(this, name);
this.age = age;
}
// 继承方法
// 构建原型链
// 第一次调用SuperType()
SubType.prototype = new SuperType();
// 重写SubType.prototype的constructor属性,指向自己的构造函数SubType
SubType.prototype.constructor = SubType;
var instance1 = new SubType("Nicholas", 29);
缺点:
- 实际上子类上会拥有超类的两份属性,只是子类的属性覆盖了超类的属性
(第一次调用SuperType()给SubType.prototype写入两个属性name,color。给instance1写入两个属性name,color)
4.原型式继承
- 利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。
function object(obj){
function F(){}
F.prototype=obj;
return new F()
}
object()对传入其中的对象执行了一次浅复制,将构造函数F的原型直接指向传入的对象。
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
ES5中存在Object.create()的方法,能够代替上面的object方法
缺点
- 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能
- 无法传递参数
优点
- 可以继承非构造函数(以上例子就是)
5.寄生式继承
- 在原型式继承的基础上,增强对象,返回构造函数。
function createAnother(original){
var clone = object(original); // 通过调用 object() 函数创建一个新对象
clone.sayHi = function(){ // 以某种方式来增强对象
alert("hi");
};
return clone; // 返回这个对象
}
- 函数的主要作用是为构造函数新增属性和方法,以增强函数
缺点
- 同原型继承
6.寄生组合继承
- 结合借用构造函数传递参数和寄生模式实现继承
function inheritPrototype(subType, superType){
var prototype=Object.create(surperType.prototype);// 创建对象,创建父类原型的一个副本
prototype.constructor=subType;// 增强对象,弥补因重写原型而失去的默认的constructor 属性
subType.prototype=prototype;// 增强对象,弥补因重写原型而失去的默认的constructor 属性
}
// 父类初始化实例属性和原型属性
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
// 借用构造函数传递增强子类实例属性(支持传参和避免篡改)
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
/ /将父类原型指向子类
inheritPrototype(SubType, SuperType);
// 新增子类原型属性
SubType.prototype.sayAge = function(){
alert(this.age);
}
缺点
- 完美实现继承,解决了组合式继承带两份属性的问题