1. 原型链继承
- 实现方式:将子类的原型链指向父类的对象实例
function Parent(){
this.name = "parent";
this.list = ['a'];
}
Parent.prototype.sayHi = function(){
console.log('hi');
}
function Child(){
}
Child.prototype = new Parent();
var child = new Child();
console.log(child.name);
child.sayHi();
var a = new Child();
var b = new Child();
a.list.push('b');
console.log(b.list); // ['a','b']
原理:子类实例child的__proto__指向Child的原型链prototype,而Child.prototype指向Parent类的对象实例,该父类对象实例的__proto__指向Parent.prototype,所以Child可继承Parent的构造函数属性、方法和原型链属性、方法
优点:可继承构造函数的属性,父类构造函数的属性,父类原型的属性
缺点:无法向父类构造函数传参;且所有实例共享父类实例的属性,若父类共有属性为引用类型,一个子类实例更改父类构造函数共有属性时会导致继承的共有属性发生变化;
2. 构造函数继承
- 实现方式 :在子类构造函数中使用call或者apply劫持父类构造函数方法,并传入参数
function Parent(name){
this.name = name;
this.type = ['JS','HTML','CSS'];
this.printName = function(){
console.log(this.name);
}
}
Parent.prototype.sayName = function(){
console.log(this.name);
};
function Son(name){
Parent.call(this,name);
// Parent.apply(this,arguments);
}
son1 = new Son("jin");
son1.type.push('VUE');
console.log(son1.type);//['JS','HTML','CSS','VUE']
son2 = new Son();
console.log(son2.type);//['JS','HTML','CSS']
son1.printName(); // jin
son1.sayName() // Error
原理:使用call或者apply更改子类函数的作用域,使this执行父类构造函数,子类因此可以继承父类共有属性
优点:可解决原型链继承的缺点
缺点:不可继承父类的原型链方法,构造函数不可复用
3. 组合继承
- 利用原型链继承和构造函数继承的各自优势进行组合使用
function Parent(name){
this.name = name;
this.type = ['JS','HTML','CSS'];
}
Parent.prototype.Say=function(){
console.log(this.name);
}
function Son(name){
Parent.call(this,name);
}
Son.prototype = new Parent();
son1 = new Son('张三');
son2 = new Son('李四');
son1.type.push('VUE');
son2.type.push('PHP');
console.log(son1.type);//['JS','HTML','CSS','VUE']
console.log(son2.type);//['JS','HTML','CSS','PHP']
son1.Say();//张三
son2.Say();//李四
优点:
①利用原型链继承,实现原型对象方法的继承
②利用构造函数继承,实现属性的继承,而且可以参数
组合函数基本满足了JS的继承,比较常用
缺点:
无论什么情况下,都会调用两次父级构造函数:一次是在创建子级原型的时候,另一次是在子级构造函数内部
4.原型式继承
- 创建一个函数,将参数作为一个对象的原型对象
function fun(obj) {
function Son(){};
Son.prototype = obj;
return new Son();
}
var parent = {
name:'张三'
}
var son1 = fun(parent);
var son2 = fun(parent);
console.log(son1.name);//张三
console.log(son2.name);//张三
优缺点:跟原型链类似
5.寄生继承
- 在原型式继承的基础上,在函数内部丰富对象
function fun(obj) {
function Son() { };
Son.prototype = obj;
return new Son();
}
function JiSheng(obj) {
var clone = fun(obj);
clone.Say = function () {
console.log('我是新增的方法');
}
return clone;
}
var parent = {
name: '张三'
}
var parent1 = JiSheng(parent);
var parent2 = JiSheng(parent);
console.log(parent2.Say==parent1.Say);// false
function JiSheng(obj) {
var clone = Object.create(obj);
clone.Say = function () {
console.log('我是新增的方法');
}
return clone;
}
var parent = {
name: '张三'
}
var parent1 = JiSheng(parent);
var parent2 = JiSheng(parent);
console.log(parent2.Say==parent1.Say);// false
优缺点:跟构造函数继承类似,调用一次函数就得创建一遍方法,无法实现函数复用,效率较低
这里补充一个知识点,ES5有一个新的方法Object.create(),这个方法相当于封装了原型式继承。这个方法可以接收两个参数:第一个是新对象的原型对象(可选的),第二个是新对象新增属性,
6.寄生组合式继承
- 原理:改进组合继承,利用寄生式继承的思想继承原型
function JiSheng(son,parent) {
var clone = Object.create(parent.prototype);//创建对象
son.prototype = clone; //指定对象
clone.constructor = son; //增强对象
}
function Parent(name){
this.name = name;
this.type = ['JS','HTML','CSS'];
}
Parent.prototype.Say=function(){
console.log(this.name);
}
function Son(name){
Parent.call(this,name);
}
JiSheng(Son,Parent);
son1 = new Son('张三');
son2 = new Son('李四');
son1.type.push('VUE');
son2.type.push('PHP');
console.log(son1.type);//['JS','HTML','CSS','VUE']
console.log(son2.type);//['JS','HTML','CSS','PHP']
son1.Say();//张三
son2.Say();//李四